Azure Linux Web App(PHP)环境下超过2MB的文件下载失败问题求助
解决Azure App Service Linux上PHP大文件下载挂起的问题
我之前在迁移客户的PHP应用到Azure App Service Linux时,也遇到了完全一样的大文件下载超时问题,折腾了好几天才找到靠谱的解决方案,给你几个亲测有效的方向:
方案1:用Apache的X-Sendfile模块(最推荐)
这是效率最高的方法,把文件发送的工作交给Apache处理,避免PHP进程长时间占用内存和超时。
- 首先在你的项目根目录的
.htaccess文件里添加以下配置,启用X-Sendfile:SetEnv MOD_X_SENDFILE_ENABLED On - 然后修改PHP下载脚本,替换原来的
readfile()调用,改用X-Sendfile头部:header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=' . basename($zipfile)); header('Expires: 0'); header('Content-Length: ' . $zipFileSize); header('Cache-Control: must-revalidate'); header('Pragma: public'); // 关键替换:让Apache直接处理文件发送 header('X-Sendfile: ' . $zipfile); exit; - 重要提示:因为你的文件存储在网站结构之外的安全目录,需要确保Apache允许访问该目录。可以在App Service的Apache配置里添加(如果有权限修改的话):
如果你没法直接修改Apache主配置,也可以尝试在XSendFilePath /path/to/your/secure/directory.htaccess里添加这条指令(部分环境支持)。
方案2:优化分块读取的脚本逻辑
如果X-Sendfile用不了,那就要优化分块读取的代码,避免超时和内存堆积:
set_time_limit(0); // 取消执行时间限制 ob_end_clean(); // 关闭所有输出缓冲,避免内存溢出 ob_implicit_flush(true); // 自动刷新输出 $chunkSize = 8 * 1024 * 1024; // 8MB块,比小块效率更高 $handle = fopen($zipfile, 'rb'); if ($handle === false) { // 处理文件打开失败的情况 http_response_code(500); exit('无法打开文件'); } while (!feof($handle)) { echo fread($handle, $chunkSize); flush(); // 强制把内容发送给客户端 usleep(50000); // 短暂停顿50ms,减轻服务器压力 } fclose($handle); exit;
同时要调整Azure的相关设置:
- 登录Azure门户,找到你的App Service,进入配置 -> 常规设置,把请求超时调大到300秒(5分钟)
- 在PHP配置里(可以通过App Service的配置 -> 应用程序设置添加
max_execution_time = 0)
方案3:检查App Service的层级和附加限制
- 如果你的App Service用的是免费/共享层级,这类层级有严格的带宽和资源限制,大文件下载很容易失败,建议升级到基本/标准层级
- 如果配置了Azure Front Door或者CDN,要检查这些服务的大文件传输限制,调整对应的超时和文件大小阈值
关键注意事项
- 确保Web服务器进程(Linux下通常是
www-data用户)有读取你的安全目录文件的权限,否则会出现权限不足的错误 - 测试时先从小文件(比如5MB)开始验证,再逐步测试到64MB的最大文件
- 可以在
.htaccess里添加SetEnv no-gzip 1,禁用gzip压缩,避免压缩过程导致的缓冲超时
内容的提问来源于stack exchange,提问作者jeHaw Services




