当前位置: 首页 > java >正文

✨ 使用 Flask 实现头像文件上传与加载功能

文章目录

      • 🧱 技术栈
      • 🗂️ 项目结构与配置
      • 🔐 用户身份校验逻辑
      • 📤 头像上传接口:`/file/avatar/upload`
      • 📥 加载头像接口:`/file/avatar/load/<filename>`
      • 🧪 示例请求(使用 cURL 测试)
        • 上传头像
        • 加载头像
      • 🔒 安全性与优化建议

在 Web 应用中,文件上传是一个非常常见且不可或缺的需求,尤其是在涉及用户头像、图片展示等功能时。本文将基于 Flask 框架,结合简单的用户身份验证逻辑,实现一个完整的“头像上传与加载”模块。


🧱 技术栈

我们的模块采用了一套简洁而高效的技术栈:

  • 后端框架: Flask
  • 数据库: MySQL(通过自定义的 SQL.DatabasePool 封装类访问)
  • 缓存: Flask-Caching(示例中配置为 simple 缓存)
  • 安全处理: 文件名加密、路径过滤、防止目录遍历攻击

🗂️ 项目结构与配置

首先,我们定义好上传文件的保存路径。这确保了所有头像都存储在一个集中且易于访问的位置:

import osBASE_DIR = os.path.dirname(os.path.abspath(__file__))
# 假设 'apps/fileManage' 是一个子模块,调整 BASE_DIR 到项目根目录
BASE_DIR = BASE_DIR.split(r"\apps\fileManage")[0]
UPLOAD_FOLDER = os.path.join(BASE_DIR, 'uploads')
os.makedirs(UPLOAD_FOLDER, exist_ok=True)

这段代码保证了以下几点:

  • 上传文件将位于项目根目录下的 uploads 文件夹中。
  • 如果 uploads 文件夹不存在,它将自动创建,避免常见的系统错误。

🔐 用户身份校验逻辑

在执行任何文件操作之前,服务器会通过检查传入 Cookie 中的 token 字段来验证用户身份。这一关键步骤确保只有授权用户才能上传或访问文件。

# 假设 'request' 已从 flask 导入
cookie = request.headers.get('Cookie')
# ... 额外解析以从 cookie 字符串中提取 token
token = dict1.get('token') # 假设 dict1 已填充 cookie 键值对
res = sql.executeQuery("SELECT userId FROM onlineUsers JOIN users ON onlineUsers.SessionId = users.userId WHERE onlineUsers.SessionId = '{}'".format(token)
)

如果用户未登录或会话失效,服务器将返回 401 Unauthorized 错误,从而保护您的应用程序免受未经授权的访问。


📤 头像上传接口:/file/avatar/upload

POST 接口负责处理头像图片的上传。完整的流程设计注重鲁棒性和安全性:

  1. 身份验证: 系统首先解析 Cookie 并验证用户会话的合法性。
  2. 文件校验:
    • 它会验证请求中是否存在文件(file 对象)。
    • 文件名不能为空。
    • 至关重要的是,只允许图片文件扩展名(.png.jpg.jpeg.gif),防止上传潜在的恶意文件类型。
  3. 重命名处理: 为了避免命名冲突并确保每个头像都有一个唯一的标识符,文件名会使用 MD5 进行哈希处理,结合用户名和原始文件名生成一个唯一字符串,并附加原始文件扩展名。
  4. 文件保存: 经验证和重命名的文件随后安全地保存到服务器上指定的 uploads 目录中。
  5. 数据库更新: 新上传头像的路径会更新到 users 表中,将头像与相应的用户关联起来。
  6. 返回结果: 成功消息以及可访问的文件路径会返回给客户端。

核心实现代码如下:

# 假设 'request' 已从 flask 导入,并且 'encrypt' 和 'sql' 已定义
file = request.files['file']
# 使用用户名和原始文件名的 MD5 哈希生成唯一文件名
newFilename = encrypt.hash_md5(username + file.filename) + '.' + file.filename.split('.')[-1]
file.save(os.path.join(UPLOAD_FOLDER, newFilename))
# 更新数据库中用户的头像路径
sql.executeUpdate("UPDATE users SET avatar = 'server:{}' WHERE userId = {}".format(newFilename, userId))

📥 加载头像接口:/file/avatar/load/<filename>

GET 接口根据唯一的头像文件名提供已上传的图片资源。它包含了多项安全和性能增强:

  • 路径过滤: 这是一项关键的安全措施,可防止用户在文件名中构造 ../ 序列,从而尝试进行目录遍历攻击并访问 uploads 目录之外的未经授权的文件。
  • 后缀验证: 只允许提供图片文件类型,防止暴露非图片文件。
  • 缓存处理: 该接口支持浏览器缓存,通过减少服务器请求显著提高频繁访问头像的性能。(更多内容请参阅“安全性与优化建议”部分。)
  • MIME 类型推断: 服务器会根据文件扩展名自动推断并设置响应的适当 Content-Type(MIME 类型)(例如,image/pngimage/jpeg),确保浏览器正确渲染图像。
# 假设 'Response' 已从 flask 导入,并且 'data' 包含图像内容
mimetype = f'image/{filename.rsplit(".", 1)[-1].lower()}'
return Response(data, mimetype=mimetype)

🧪 示例请求(使用 cURL 测试)

为了帮助您测试和理解 API 交互,以下是上传和加载头像的 cURL 命令:

上传头像
curl -X POST http://yourdomain.com/file/avatar/upload \-H "Cookie: token=YOUR_TOKEN" \-F "file=@/path/to/your/avatar.png"

请将 YOUR_TOKEN 替换为有效的用户会话令牌,将 /path/to/your/avatar.png 替换为您的图片文件的实际路径。

加载头像
curl http://yourdomain.com/file/avatar/load/xxxxxx.png --output avatar.png

请将 xxxxxx.png 替换为您希望加载的头像的实际唯一文件名。--output avatar.png 标志会将下载的图像保存为 avatar.png 文件。


🔒 安全性与优化建议

虽然我们的模块提供了坚实的基础,但对于生产环境,请考虑以下额外的措施:

  • 文件名哈希: 已实现,这一关键步骤通过确保唯一文件名来防止用户互相覆盖文件。

  • 路径遍历保护: 已实现,这可以防止恶意用户访问指定上传目录之外的文件。

  • 文件大小限制: 实现服务器端检查以限制最大文件大小。这可以防止由于上传过大文件而导致的拒绝服务攻击,并节省服务器资源。

  • 健壮的错误处理: 增强文件操作的错误处理(例如,磁盘已满、权限问题),以便为用户和管理员提供更具信息量的反馈。

  • 云存储集成: 对于生产环境,特别是流量较高的场景,请考虑将头像存储卸载到专门的云存储解决方案,如阿里云 OSS七牛云Amazon S3。这可以显著提高可伸缩性、可靠性,并减轻应用程序服务器的负担。

  • 浏览器缓存以提高性能: 明确地为头像等静态资源向 Response 添加 Cache-Control 头。这允许浏览器缓存图像,从而加快后续加载速度并减少服务器负载。

    return Response(data, mimetype=mimetype, headers={'Cache-Control': 'public, max-age=86400'})
    

    此头信息告诉浏览器将图像缓存 24 小时(86400 秒)。

http://www.xdnf.cn/news/16280.html

相关文章:

  • 工业缺陷检测的计算机视觉方法总结
  • 【C++ python cython】C++如何调用python,python 运行速度如何提高?
  • 工程项目管理软件评测:13款热门平台一览
  • mysql 和oracle的选择
  • JMeter每次压测前清除全部以确保异常率准确(以黑马点评为例、详细图解)
  • Springboot整合springmvc
  • 微信小程序动态切换窗口主题色
  • SpringBoot3(若依框架)集成Mybatis-Plus和单元测试功能,以及问题解决
  • 全面解析MySQL(3)——CRUD进阶与数据库约束:构建健壮数据系统的基石
  • 关于回归决策树CART生成算法中的最优化算法详解
  • Android Kotlin 协程全面指南
  • 详解软件需求中的外部接口需求
  • 线性代数 上
  • 【MAC的VSCode使用】
  • docker compose xtify-music-web
  • 【数据库】探索DBeaver:一款强大的免费开源数据库管理工具
  • HANA语法随手记:<> ‘NULL‘值问题
  • 七层网络的瑞士军刀 - 服务网格 Istio 流量管理
  • HTTP响应状态码详解
  • 快速入门Socket编程——封装一套便捷的Socket编程——Reactor
  • 关于自定义域和 GitHub Pages(Windows)
  • 基于springboot的候鸟监测管理系统
  • pycharm安装教程-PyCharm2023安装详细步骤【MAC版】【安装包自取】
  • Logstash 多表增量同步 MySQL 到 Elasticsearch:支持逻辑删除与热加载,Docker 快速部署实战
  • 【Android】桌面小组件开发
  • RAG面试内容整理-3. 向量检索原理与常用库(ANN、FAISS、Milvus 等)
  • 三坐标和激光跟踪仪的区别
  • 【源力觉醒 创作者计划】ERNIE-4.5-VL-28B-A3B 模型详解:部署、测试与 Qwen3 深度对比测评
  • OmoFun网页版官网入口,动漫共和国最新地址|官方下载地|打不开
  • Cacti命令执行漏洞分析(CVE-2022-46169)