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

Apache 2.4.61下PHP设置Content-Length无效致下载进度异常问题

文件下载Content-Length头失效问题解决

问题描述

文件下载功能出现异常:已通过PHP设置Content-Length响应头,但该头未生效,XMLHttpRequest的progress事件中lengthComputable无法正确获取。服务器版本为Apache 2.4.61。

已知情况:

  • 文件路径配置正确,filesize()函数返回值准确
  • 响应中未包含Content-Length头,反而返回Transfer-Encoding: chunked
  • 目前临时方案是添加自定义Alternate-Content-Length头来更新进度条,需实现正常使用Content-Length的非分块下载

相关代码

PHP代码

<?php
header('Content-Description: File Transfer');
header("Content-Type: application/force-download");
header("Content-Disposition: attachment; filename=" . $nomFichier);
header("Pragma: no-cache");
header("Expires: 0");
header("Content-Length: " . filesize($cheminFichier));

JS代码

function update_progress(e, elProgress) {
  if (e.lengthComputable) {
    var percentage = Math.round((e.loaded / e.total) * 100);
    
    if (elProgress) {
      var elProgress = jQuery(elProgress);
      elProgress.find('.progressBar').css('width', percentage + '%');
      elProgress.parent(".linkDetails").find('.progressPercent').html(percentage + '%');
    } else {
      jQuery(".progressBar").css('width', percentage + '%');
      jQuery(".progressPercent").html(percentage + '%');
    }
  } else {
    console.log("Unable to compute progress information since the total size is unknown");
  }
}

解决方案

1. 禁用Apache输出压缩

Apache的mod_deflate/mod_gzip开启时会自动压缩输出,导致Content-Length被忽略,转而使用分块编码。可通过两种方式处理:

  • 在PHP代码中强制禁用压缩:
    header('Content-Encoding: none');
    
  • 在.htaccess或Apache主配置中对特定文件类型禁用压缩:
    SetEnvIfNoCase Request_URI "\.(zip|rar|pdf|exe|doc|xls)$" no-gzip dont-vary
    

2. 关闭PHP输出缓冲

PHP输出缓冲开启时,服务器无法提前确定最终输出大小,会自动切换到分块编码。解决方法:

  • 在PHP代码开头添加:
    ob_end_clean(); // 关闭并清空输出缓冲
    
  • 或修改php.ini配置:
    output_buffering = Off
    
    修改后需重启Apache生效。

3. 确保Content-Length在输出前设置

务必在任何输出(包括空格、换行、BOM)之前设置Content-Length头。如果PHP文件存在BOM或之前有echo/print等输出,会导致头信息发送异常,Content-Length被服务器忽略。

4. 检查Apache强制分块配置

检查.htaccess或Apache主配置中是否存在强制启用分块编码的配置,例如:

SetEnv force-response-1.1 1

如有则移除该配置。

5. 使用readfile()输出文件内容

如果后续是手动读取文件内容输出,建议替换为readfile()函数,它能直接输出文件内容,避免手动输出导致的大小计算偏差,更好配合Content-Length头:

readfile($cheminFichier);
exit;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 15:19:51