Django对接Azure Blob存储上传文件时Ajax进度条失效问题
Django对接Azure Blob存储时Ajax上传进度条卡住问题
问题现象
- 基于Ajax实现Django文件上传进度条功能时,使用本地文件存储(配置
upload_to参数)进度条更新完全正常 - 切换为自定义Azure Blob存储后端后,文件可以正常上传到Azure,但进度条卡住无法正常更新
- 方案约束:不采用浏览器直传、CORS、SAS令牌的前端直传方案,所有文件上传流量必须经过后端中转
复现代码
本地存储(功能正常)模型定义
class UploadFile(models.Model): title = models.CharField(max_length=50) file=models.FileField(upload_to='files/media/pre')
Azure存储(进度条异常)模型定义
from myAzure import AzureMediaStorage as AMS class UploadFile(models.Model): title = models.CharField(max_length=50) file = models.FileField(storage=AMS)
自定义Azure存储类实现(myAzure.py)
from storages.backends.azure_storage import AzureStorage class AzureMediaStorage(AzureStorage): account_name = '<myAccountName>' account_key = '<myAccountKey>' azure_container = 'media' expiration_secs = None
问题根因
前端Ajax原生的xhr.upload.progress事件,只能统计浏览器到Django服务这一段链路的上传进度,完全无法感知Django服务接收到文件之后,再中转上传到Azure Blob的第二段传输进度:
- 本地存储场景下,Django接收完浏览器上传的完整文件后,直接写入服务器本地磁盘,耗时极短,后端返回上传完成响应的时间和浏览器传完文件的时间几乎重合,所以进度条看起来可以平滑更新到100%
- Azure存储场景下,Django接收完浏览器上传的完整文件后,还需要通过公网把文件中转传输到Azure服务,这段传输耗时较长,前端在浏览器到后端的传输完成后就会把进度读到100%,之后因为拿不到后端到Azure的传输进度,就会表现为进度条卡住,直到后端完成Azure上传返回响应,进度条才会直接跳转为完成状态
修复方案(符合后端中转要求)
放弃完全依赖前端xhr进度事件的实现逻辑,改为前后端配合统计全链路进度:
- 上传流程调整:
- 每个上传任务生成唯一的任务ID,前端发起上传请求时携带该ID
- Django接收到前端上传的文件后,先存入服务器临时目录,不要直接触发Azure存储的写入逻辑
- 后端单独提供进度查询接口,接收任务ID参数,返回对应任务的实时上传进度
- 后端调用Azure Blob SDK执行文件上传,通过SDK自带的进度回调钩子,实时把上传进度写入缓存(如Redis),和任务ID绑定
- 确认文件上传到Azure完成后,更新数据库记录,清理临时文件,返回上传完成响应
- Azure SDK进度回调示例代码:
from django.core.cache import cache def azure_upload_progress_hook(current_bytes, total_bytes, task_id): progress = min(int(current_bytes / total_bytes * 100), 99) # 未完成时最高显示99% cache.set(f"upload_progress:{task_id}", progress, timeout=300) # 调用SDK上传时注册钩子 blob_client.upload_blob( temp_file, progress_hook=lambda current, total: azure_upload_progress_hook(current, total, task_id), overwrite=True ) # 上传完成后把进度置为100 cache.set(f"upload_progress:{task_id}", 100, timeout=300)
- 前端逻辑调整:
- 发起上传请求后,启动定时轮询,每300ms调用一次进度查询接口,传入当前任务ID
- 拿到接口返回的进度值后,实时更新进度条宽度/百分比显示
- 收到上传完成的接口响应后,停止轮询,将进度条置为100%状态即可
内容的提问来源于stack exchange,提问作者Binyamin Even
相关产品推荐
相关产品推荐

