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

Django返回含文件数据的响应异常 前端无限处于请求加载状态

问题根因

该问题90%以上的概率由以下两个原因导致,按出现优先级排序:

  • Content-Length响应头值与实际文件大小不匹配:你在代码中手动将Content-Length设置为数据库字段存储的instance.size,如果该值和实际下载到/tmp目录的文件真实字节数存在偏差(常见场景包括S3源文件被覆盖修改、文件入库时大小统计错误、下载过程中网络波动导致临时文件截断),尤其是当设置的Content-Length大于文件实际大小时,客户端会严格按照响应头声明的长度等待接收剩余数据,就会一直卡在“加载中”状态直到超时。这也完全符合你观察到的现象:后端逻辑已经执行完成、进程没有被阻塞可以正常响应其他请求,但客户端始终收不到“响应结束”的信号。
  • 流式传输逻辑被中间件打断或文件资源泄漏:你手动调用open()打开文件后传入FileWrapper,如果使用的WSGI服务没有正确触发文件关闭逻辑,会导致传输中断;另外你部署的Django Silk监控中间件默认会拉取全量响应体做性能统计,对于流式响应会尝试将所有分块读入内存再返回,配置不当时会直接打断分块传输流程,导致客户端无法接收到完整数据。

你之前替换FileResponse没有解决问题,大概率是替换后仍然保留了手动设置错误Content-Length的逻辑,覆盖了FileResponse自动生成的正确头值。

修复步骤
  1. 修正Content-Length的取值逻辑,不要直接使用数据库存储的历史值,改为读取临时文件的真实大小,同时补充文件句柄的关闭逻辑:
    import os
    # 原有业务逻辑省略
    if status_code == 200:
        fp = open(file_path, 'rb')
        # 读取打开文件的真实大小
        real_size = os.fstat(fp.fileno()).st_size
        response = StreamingHttpResponse(
            FileWrapper(fp, chunk_size),
            content_type=instance.mime_type
        )
        response['Content-Length'] = real_size
        response['Content-Disposition'] = f"attachment; filename={instance.file_name}"
        # 注册响应结束后的文件关闭逻辑
        response.close = fp.close
        return response
    
  2. 更稳妥的方式是直接使用Django内置的FileResponse,它内部已经封装了FileWrapper适配、真实文件大小读取、文件句柄自动回收的逻辑,不需要手动实现易出错的底层细节:
    from django.http import FileResponse
    # 原有业务逻辑省略
    if status_code == 200:
        return FileResponse(
            open(file_path, 'rb'),
            content_type=instance.mime_type,
            filename=instance.file_name,
            as_attachment=True
        )
    
    注意:使用FileResponse时不要手动设置Content-Length头,避免覆盖框架自动生成的正确值。
  3. 调整Django Silk配置,避免监控中间件打断流式传输:
    在项目配置文件中添加如下规则,让Silk跳过媒体下载接口的响应体采集:
    # 跳过指定路径的监控
    SILK_IGNORE_PATHS = [
        r'^/your-media-api-prefix/',
    ]
    # 或者全局关闭响应体捕获功能
    SILK_CAPTURE_RESPONSE_BODY = False
    
  4. 补充临时文件回收逻辑:当前实现中下载到/tmp目录的文件没有自动清理机制,长期运行会占满磁盘空间,建议改用tempfile模块创建临时文件,文件句柄关闭后会自动删除对应文件。

验证方式:修改完成后抓包查看接口返回的Content-Length值,和服务器本地/tmp目录下对应临时文件的实际大小做比对,两个值完全一致时,客户端无限加载的问题即可解决。

内容的提问来源于stack exchange,提问作者Dmitriy Lunev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 05:24:28