Nginx 上传文件报 413 Request Entity Too Large 是 client_max_body_size
问题现象 运营后台上线一个"批量导入 Excel"的功能,前端用 form 表单 POST 上传。本地和测试环境都好好的,一上生产就出问题:文件稍大一点(十几 MB)点提交,浏览器直接弹 413,页面没有任何后端日志,Nginx 的 access log 里能看到那条请求返回 413,error log 却干干净净。小文件(几百 KB)正常,临界点大概在 1MB 左右,超过就必现。前端同学一度怀疑是后端接口挂了,后端同学看自己日志又确实没收到请求,两边互相甩锅。
排查过程 先怀疑是后端服务的上传大小限制,比如 Spring 的 max-file-size、Node 的 body-parser limit、PHP 的 upload_max_filesize。把这几个配置翻了一遍,在测试环境把阀值设得很小也复现不出来,说明不是应用层的问题。 再用 curl 在服务器本地复现:curl -F "file=@big.xlsx" https://upload.example.com/api/import,同样直接返回 413,响应体就一行 "413 Request Entity Too Large",后端日志依旧空白。这基本坐实是 Nginx 这一层干的。 看 Nginx access log,那条请求的 $body_bytes_sent 是 0、$request_length 也很小,说明连接刚把请求头收完、还没(或刚开始)收请求体就被断了,根本没进到 upstream。这就指向 Nginx 在把请求体转发给后端之前就把请求拦了。 在 Nginx 配置里 grep client_max_body_size,发现 http 块里压根没显式配过,全靠默认值。Nginx 这个指令默认就是 1m。一测,1MB 出头就 413,临界点和现象完全对得上,根因锁定。
根因 client_max_body_size 控制 Nginx 允许客户端请求体的最大尺寸,默认 1m。一旦请求体(对上传来说基本就是文件本身)超过这个值,Nginx 在接收阶段就直接返回 413,连后端都不通知。这个限制是"入口侧"的,和后端框架自己的上传限制是两回事。这两层经常得都配上,但很多人只记得配后端,忘了 Nginx 这层,于是前端报错、后端无日志,典型被网关拦在门外。如果整套链路前面还垫了 CDN、WAF 或另一层反向代理,那些节点也各自有 body 上限,漏掉任何一层都会重复踩坑。
解决办法 在对应的 server 或 location 块里加上(按业务需要调大,别无脑设 0):
server {
listen 80;
server_name upload.example.com;
client_max_body_size 50m; # 允许最大 50MB 上传
location /api/import {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
改完 nginx -t 校验语法,再 nginx -s reload 平滑加载。注意三处作用域:http 全局、server、location,就近覆盖,所以最好直接配在出问题的 location 里最稳,避免误伤其他接口。另外后端也要同步放开(如 Spring spring.servlet.multipart.max-file-size=50MB),否则会变成后端再报一次 400/500;如果前面还有 WAF/CDN,它们的 body 上限也要一并调。可以在 log_format 里加上 $body_bytes_sent、$request_length,方便以后一眼看出是谁在传大文件。想给用户友好提示,还可以配 error_page 413 /413.html; 自定义报错页。Docker 部署时记得改的是挂载进容器的 conf,reload 的是正在运行的实例,别改了镜像里那份却没生效。
小结 413 不一定是后端问题,Nginx 的 client_max_body_size 默认 1m 是高频踩坑点。定位口诀:先看 access log 返没返 413、后端有没有收到请求、curl 能不能本地复现——没收到就是 Nginx 自己拦的。前端报错、后端无日志,八成就是这层。改配置记得 nginx -t + reload,并且前后端、以及任何中间层限制一起对齐,别只改一边。
- 点赞
- 收藏
- 关注作者
评论(0)