You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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进度事件的实现逻辑,改为前后端配合统计全链路进度:

  • 上传流程调整:
    1. 每个上传任务生成唯一的任务ID,前端发起上传请求时携带该ID
    2. Django接收到前端上传的文件后,先存入服务器临时目录,不要直接触发Azure存储的写入逻辑
    3. 后端单独提供进度查询接口,接收任务ID参数,返回对应任务的实时上传进度
    4. 后端调用Azure Blob SDK执行文件上传,通过SDK自带的进度回调钩子,实时把上传进度写入缓存(如Redis),和任务ID绑定
    5. 确认文件上传到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)
  • 前端逻辑调整:
    1. 发起上传请求后,启动定时轮询,每300ms调用一次进度查询接口,传入当前任务ID
    2. 拿到接口返回的进度值后,实时更新进度条宽度/百分比显示
    3. 收到上传完成的接口响应后,停止轮询,将进度条置为100%状态即可

内容的提问来源于stack exchange,提问作者Binyamin Even

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 02:21:28