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配置:
修改后需重启Apache生效。output_buffering = Off
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
相关产品推荐
相关产品推荐

