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

为何XMLHttpRequest的event.total始终为0,仅Content-Type为PDF时正常?

问题核心原因

你遇到的问题是Apache的mod_deflate(gzip压缩模块)的默认规则导致的:

  • Apache默认会对所有text/*类型的响应(比如你设置的text/plain)自动执行gzip压缩
  • 压缩是边传输边生成的,无法提前计算最终压缩后的文件大小,所以Apache会自动删除你代码里设置的Content-Length响应头,替换为Transfer-Encoding: chunked分块传输
  • 而application/pdf、application/octet-stream这类非文本的MIME类型,不在mod_deflate的默认压缩列表里,所以不会被压缩,你设置的Content-Length头可以正常保留,前端就能拿到event.total的值

你控制台返回的响应头里同时存在content-encoding: gzip和transfer-encoding: chunked,已经验证了这个判断。


可行的解决办法

如果你需要保留text/plain类型,又想正常拿到下载进度,可以选择以下任意一种方案:

方案1:针对该下载接口关闭gzip压缩

可以在backend.php代码里加一行响应头,主动告诉Apache不要压缩当前响应:

header('Content-Encoding: none');

也可以在.htaccess里添加规则,针对该后端路径关闭压缩:

SetEnvIf Request_URI ^/backend.php no-gzip dont-vary

方案2:保留压缩,自定义头传递原始文件大小

如果你需要保留gzip压缩节省带宽,可以在后端额外加一个自定义头传递原始文件大小,前端从自定义头里取值当total:
后端PHP添加:

header('X-Original-Content-Length: ' . filesize($file));

然后别忘了在.htaccess的Access-Control-Expose-Headers里加上这个自定义头:

Header add Access-Control-Expose-Headers "Content-Length, X-Original-Content-Length"

前端进度事件里直接取这个头的值即可:

const total = oReq.getResponseHeader('X-Original-Content-Length')

方案3:修改Apache的mod_deflate压缩规则,排除你需要的文本类型(不推荐)

这种方式会影响全局所有同类型响应,没必要单独为下载接口调整。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 13:15:02