用户后台传一张 3MB 的图,页面转半天最后白屏,什么提示都没有。你去看浏览器请求,状态码 413 Request Entity Too Large。这个错误有个讨厌的特性:官方文档里明确写了浏览器没法正确渲染它,所以用户端看到往往不是 413 页面,而是一片白或者连接被重置,报障的时候只会说“传不上去”。
根因就一句话:Nginx 的 client_max_body_size 默认 1MB,请求体超过就直接拒,连后端的面都见不到。但很多人改完 Nginx 还是传不上去,是因为上传链路上一共卡着三道限制,只改一道等于没改。
# 第一道:Nginx(http/server/location 都可以设,location 优先级最高)
http {
client_max_body_size 100m;
client_body_buffer_size 128k; # 超过缓冲区的请求体会落盘临时文件
client_body_timeout 300s; # 大文件上传时默认 60s 可能不够
}
# 第二道:PHP 自身的上传限制(php.ini 或 FPM 的 conf.d 片段)
upload_max_filesize = 100M
post_max_size = 100M # 必须大于等于 upload_max_filesize
memory_limit = 256M # 官方建议 memory_limit 要比 post_max_size 大
# 第三道:FPM/Nginx 的超时,大文件传一半被掐断报的又是另一个错
# nginx: fastcgi_read_timeout 300; fastcgi: request_terminate_timeout = 300s
改完先做配置检查再重载,然后验证实际生效的值——用 nginx -T 把全量配置导出来 grep,比逐个文件翻靠谱,因为 client_max_body_size 可能同时写在 http 块、站点配置和某个 include 里,冲突时取的是最内层作用域的值。
nginx -t && systemctl reload nginx
# 确认当前生效的所有限制值
nginx -T 2>/dev/null | grep -n client_max_body_size
# PHP 侧确认(注意 FPM 和 CLI 是两套 php.ini,别改错对象)
php -i | grep -E "upload_max_filesize|post_max_size" # CLI
# FPM 侧建一个含
# 用 curl 直接验证 413 是否消失:造一个 5MB 的测试文件上传
dd if=/dev/zero of=/tmp/test5m.bin bs=1M count=5
curl -sS -o /dev/null -w "status:%{http_code}
" \
-F "file=@/tmp/test5m.bin" https://你的域名/upload
curl 返回 200 就算通了。如果还是 413,去看 Nginx 的 error.log,里面会有一句非常明确的特征日志:client intended to send too large body,后面跟着具体字节数,对一下这个数就知道是哪一层在拦。另外提醒一句,如果前面还套了 CDN 或者第二层反代,每一层 Nginx 都要放行,只改源站这一层,边缘节点照样把你拦下来。
最后说下 size 0 这个选项:client_max_body_size 0 表示完全不限制请求体,能省事但等于把资源耗尽型攻击的门拆了,生产环境不建议。按业务给每个 location 设不同上限——上传接口 500m、普通 API 5m,才是正确用法。
收尾多说一句这个错误的观感问题:因为浏览器渲染不了 413 页面,用户报障永远只会说“上传失败”或者“网站坏了”,你从报障描述里根本看不出是大小问题。所以凡是有上传功能的站点,建议把 413 做成自定义错误页并在前端提前校验文件大小,用 JS 在提交前拦一道给出明确提示,服务端的这道闸留着兜底就行——体验和防护两头都占。
相关阅读:413 属于接入层的限制类故障。《服务器故障排查总纲:按现象反查的五层定位法》按现象把 502、403、413 这些报错各归其位,出事先翻总纲定层,再进单篇动手。
申请创业报道,分享创业好点子。点击此处,共同探讨创业新机遇!
