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

为什么 upload_max_filesize 改了还是 413?
因为 Nginx 或 Apache 拦在 PHP 前面,php.ini 的设置根本没机会生效。Laravel 内部的验证(比如 request()->validate(['file' => 'max:10240']))也只会报 422,不是 413——那说明请求压根没进 Laravel。
- Nginx 需同步加
client_max_body_size 100M(写在http、server或location块里,别漏 reload) - Apache 要确认
LimitRequestBody没被设成小值(默认无限制,但某些托管环境会锁死) - Cloudflare 等代理层也会截断大请求,临时关闭或调高
Max Upload Size设置
Laravel 里怎么接分片上传的 POST /upload/chunk?
分片上传本质是多次小请求拼一个大文件,关键不在“传”,而在“合”。Laravel 不内置分片逻辑,得自己管好:分片标识、临时存储、合并时机、失败回滚。
- 每个分片带必要元数据:
filename、identifier(如 hash)、chunkNumber、totalChunks、size - 用
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推导并持久化(比如存 Redis:upload:{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() - 分片文件存在本地磁盘(
localdriver)时更快;用s3驱动需先Storage::download()到临时路径再合并 - 合并完立刻删分片:
Storage::delete($chunkPaths),避免磁盘占满又查不到是谁传的 - 用
set_time_limit(0)防超时,但更稳妥的是把合并逻辑扔进队列(dispatch(new MergeUploadJob($identifier)))
分片上传真正难的不是接口写法,是各环节状态一致性——比如用户关浏览器、网络中断、服务重启后,怎么知道该续传还是重来。这些没法靠框架自动兜底,得靠 identifier + Redis 记录每片状态 + 定期清理过期任务。










