根本原因是php底层限制与web服务器超时共同导致,需同步调整php.ini(upload_max_filesize、post_max_size、max_execution_time、memory_limit)和nginx/apache(client_max_body_size、timeout等)配置,而分片上传通过拆分请求规避全部瓶颈。

不是 Laravel 本身超时,而是 PHP 的底层限制和同步阻塞处理方式共同导致的。 即使你把 Laravel 控制器逻辑写得再简洁,只要走传统 multipart/form-data 直传,就绕不开 PHP 进程卡在接收完整文件、解析、内存加载这整条链路上。
PHP 配置三重枷锁必须同时解
只改 upload_max_filesize 是最常见误区。它只是第一道门,后面还有两道更硬的墙:
-
post_max_size必须 ≥upload_max_filesize,否则表单数据(含文件头)直接被 PHP 拦截,$_FILES为空,Laravel 根本收不到请求 -
max_execution_time和max_input_time都要调大——前者控制脚本总执行时间,后者专管“接收输入”阶段(包括上传文件流),默认 60 秒,200MB 文件在千兆内网都可能超 -
memory_limit不是“够用就行”,而是“必须远大于文件大小”。PHP 默认把整个上传文件读进内存再交给 Laravel 处理,1GB 文件配 512MB 内存照样 OOM
为什么调高配置后还是卡在 30 秒?
现象:Nginx/Apache 日志里出现 upstream timed out 或 504 Gateway Timeout,但 PHP 错误日志没报错——说明请求根本没进 PHP,被 Web 服务器中途掐断了。
- Nginx 默认
client_max_body_size是 1MB,不改它,php.ini改到 10G 也白搭 - Nginx 还有
client_header_timeout、client_body_timeout,大文件上传过程中若客户端发送间隔稍长(比如弱网),就会触发超时 - Apache 的
LimitRequestBody和Timeout同样需要显式放宽,且需确认是否启用mod_reqtimeout
真正有效的解法不是“加时间”,而是“不等”
分片上传的本质是把“一个长请求”拆成“几十个短请求”,每个请求只处理几 MB 数据,彻底避开 PHP 和 Web 服务器的超时阈值。
- 前端用
Uppy或原生Blob.slice()切块,每块带file_id+chunk_index+total_chunks - 后端用
storeAs()直接落盘到storage/app/chunks/,**绝不**用$request->file()->get()或file_get_contents()加载全量内容 - 合并操作(
cat或file_put_contents追加)放在所有分片收齐后,用 Artisan 命令或队列异步执行,避免阻塞 HTTP 请求 - 关键点:分片接口返回必须极快(毫秒级),不校验文件完整性、不重命名、不移动,只做存储+记录状态
最容易被忽略的是 Web 服务器层的超时设置——它比 PHP 配置更早生效,且错误信息更隐蔽。哪怕你把 PHP 的 max_execution_time 设为 0,Nginx 的 proxy_read_timeout 仍是 60 秒,上传过程卡住 61 秒就会静默失败。











