生产环境Django Rest Framework处理大量上传图片的最优方案及实现方法
DRF头像上传需求规范实现方案
几千张规模的头像上传属于非常典型的轻量资源存储场景,完全没必要把原始文件存在业务服务器,标准实现思路如下:
1. 存储层选型
- 公有云部署场景优先选择云厂商对象存储服务,比如阿里云OSS、腾讯云COS、七牛云Kodo,这类服务自带多副本冗余、CDN加速、内置图片处理能力,成本极低,几千张头像一年的存储+流量成本不到10元,不需要自己维护存储集群
- 私有部署场景可以用MinIO自建对象存储服务,API和公有云OSS完全兼容,后续要迁云也不需要改业务逻辑
2. 上传流程设计(DRF侧配合逻辑)
不要走「前端传文件到DRF→DRF再传到存储」的中转流程,中转会浪费业务服务器带宽,高并发下很容易把服务器带宽打满,推荐走前端直传方案,流程如下:
- 前端先向DRF发起上传申请,携带文件格式、文件大小等基础信息
- DRF做权限校验(比如判断当前用户是否登录、是否有上传头像的权限),校验通过后调用对象存储的SDK生成带过期时间的上传签名URL,返回给前端
- 前端拿到签名URL后直接把图片文件传到对象存储,全程不需要走业务服务器
- 上传完成后前端把最终的图片存储地址回传给DRF,后端把地址和用户信息绑定存入数据库即可
3. 头像标准化处理
头像一般需要统一尺寸、压缩体积,两种方案按需选择:
- 方案一:用对象存储的实时处理能力,上传原始图之后,只需要在返回给前端的访问URL后拼接固定的处理参数,就能自动返回裁切、压缩后的指定尺寸头像,不需要提前处理,适配多端不同尺寸需求非常方便
- 方案二:如果需要统一存储处理后的头像,DRF可以监听对象存储的上传完成回调,触发Celery异步任务,调用Pillow库完成裁切、压缩后覆盖原始文件或者存为新的处理后文件即可
4. 安全校验补充
- 后端生成签名URL前,要限制上传的文件类型(仅允许jpg/png/webp等图片格式)、文件大小(比如限制最大2M),避免恶意上传大文件或者可执行文件
- 如果有防盗图需求,可以给对象存储配置referer白名单,或者开启URL签名校验,避免头像地址被恶意盗用消耗流量
DRF生成上传签名代码示例(以阿里云OSS为例)
import time import oss2 from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated class AvatarUploadSignatureView(APIView): permission_classes = [IsAuthenticated] def get(self, request): # 初始化OSS客户端 auth = oss2.Auth('你的AccessKey', '你的AccessKeySecret') bucket = oss2.Bucket(auth, 'oss-cn-beijing.aliyuncs.com', '你的bucket名称') # 生成唯一文件名,避免覆盖:用户id+时间戳 file_name = f"avatar/{request.user.id}_{int(time.time())}.png" # 生成10分钟有效期的上传签名URL signed_url = bucket.sign_url('PUT', file_name, 600) return Response({ "signed_upload_url": signed_url, "final_access_url": f"https://你的bucket绑定域名/{file_name}" })
内容的提问来源于stack exchange,提问作者Nihad
相关产品推荐
相关产品推荐

