Laravel怎么处理大文件上传_Laravel分片上传解决方案教程【稳定】

6次阅读

413错误源于nginx/apache/cloudflare等前置代理限制,非php配置;分片上传需自行实现标识、存储、校验、流式合并与状态管理。

Laravel怎么处理大文件上传_Laravel分片上传解决方案教程【稳定】

为什么 upload_max_filesize 改了还是 413?

因为 Nginx 或 Apache 拦在 PHP 前面,php.ini 的设置根本没机会生效。laravel 内部的验证(比如 request()->validate(['file' => 'max:10240']))也只会报 422,不是 413——那说明请求压根没进 Laravel。

  • Nginx 需同步加 client_max_body_size 100M(写在 httpserverlocation 块里,别漏 reload)
  • Apache 要确认 LimitRequestBody 没被设成小值(默认无限制,但某些托管环境会锁死)
  • Cloudflare 等代理层也会截断大请求,临时关闭或调高 Max Upload Size 设置

Laravel 里怎么接分片上传的 POST /upload/chunk

分片上传本质是多次小请求拼一个大文件,关键不在“传”,而在“合”。Laravel 不内置分片逻辑,得自己管好:分片标识、临时存储、合并时机、失败回滚。

  • 每个分片带必要元数据:filenameidentifier(如 hash)、chunkNumbertotalChunkssize
  • Storage::put() 存单个分片到 storage/app/chunks/,命名建议为 {identifier}_{chunkNumber}
  • 收到最后一片时触发合并:Storage::get() 读所有分片按序拼接,再 Storage::put() 写最终文件
  • 别用 file_put_contents(..., FILE_APPEND) 直接追加——并发上传同一文件时会乱序或覆盖

前端传错 Content-Range,后端怎么安全校验?

分片上传常依赖 Content-Range 头(如 bytes 0-999999/10485760),但这个头前端可伪造,不能直接信。

  • 必须比对:chunkNumber * chunkSize 是否等于 Content-Range 的起始偏移,且 chunkSize 与实际 $request->file('file')->getSize() 一致
  • 总大小不能只靠 Content-Range 的 total 字段,要从首次上传的 totalChunks × chunkSize 推导并持久化(比如存 redisupload:{identifier}:total_size
  • 超过预设大小的分片直接 return response('', 400),不存、不合并、不报具体原因(防探测)

合并大文件时卡住或内存爆掉怎么办?

Storage::get() 一次性读所有分片进内存再拼,1GB 文件就可能吃光 2GB 内存。PHP 默认内存限制是 128MB,超了就 Fatal Error: Allowed memory size exhausted

  • 改用流式合并:fopen($finalPath, 'wb') + fopen($chunkPath, 'rb') + stream_copy_to_stream()
  • 分片文件存在本地磁盘(local driver)时更快;用 s3 驱动需先 Storage::download() 到临时路径再合并
  • 合并完立刻删分片:Storage::delete($chunkPaths),避免磁盘占满又查不到是谁传的
  • set_time_limit(0) 防超时,但更稳妥的是把合并逻辑扔进队列(dispatch(new MergeUploadJob($identifier))

分片上传真正难的不是接口写法,是各环节状态一致性——比如用户关浏览器、网络中断、服务重启后,怎么知道该续传还是重来。这些没法靠框架自动兜底,得靠 identifier + Redis 记录每片状态 + 定期清理过期任务。

text=ZqhQzanResources