nginx-413-client-max-body-size

Nginx 413 排错:client_max_body_size 加在哪一层才生效

现象

上传一个 20 多 MB 的附件,前端直接弹 413:

复制代码
413 Request Entity Too Large
nginx/1.20.2

不是超时,也不是网络中断,请求压根没进后端。

环境

  • 链路:浏览器 → Nginx(443) → 反向代理 → Spring Boot(8080)
  • 站点配置在 /etc/nginx/conf.d/app.conf
  • 后端 spring.servlet.multipart.max-request-size 早就调到 100MB 了

后端限制已经放开,所以问题不在 Java 这边。

先确认是 Nginx 拦的

这一步别跳。判断方法很简单:去看后端访问日志。

413 是 Nginx 读完请求头、发现 Content-Length 超限就直接返回的,请求不会转发给 upstream。所以如果这次上传在 Spring Boot 的 access log 里完全没有记录,而错误页又是标准的 Nginx 样式、响应头带 Server: nginx,那就基本确定拦在 Nginx 层了。

Nginx 自己的 error.log 里会留一句:

复制代码
client intended to send too large body: 25165824 bytes

看到这句就不用再怀疑了。

另外,如果这个请求是 JSON 而不是文件,client_max_body_size 一样管,它不是只针对 multipart 上传的。

加在哪

client_max_body_size 只能写在三个地方:http、server、location。作用域越小优先级越高,也就是 location > server > http。

想让整个站点生效,写在 server 块的大括号里面 ,和 listen、server_name 同级,别写进 location:

nginx 复制代码
server {
    listen 443 ssl;
    server_name example.com;

    client_max_body_size 100m;

    root /www/wwwroot/example;
    index index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
}

写在 server 块里的哪一行其实无所谓,Nginx 不靠顺序解析这个指令。我习惯塞在 server_name 下面,改的时候一眼能找到。

几个容易写错的位置:

  • 写进 http {} 外面或者 events {} 里 ------ nginx -t 直接报错,指令不允许出现在那儿
  • 写进某个 location 里 ------ 只对匹配这个 location 的请求生效,其他路径还是默认的 1m
  • 同一个 server 块里写了两次 ------ 报 "client_max_body_size" directive is duplicate,改之前先 grep 一下有没有旧值

只想放开上传接口

那就别在 server 层放大,收窄到具体路径更安全:

nginx 复制代码
server {
    listen 443 ssl;
    server_name example.com;

    location /api/upload {
        client_max_body_size 100m;
        proxy_pass http://127.0.0.1:8080;
    }
}

全站放开 100m 意味着任何一个接口都能被打 100MB 的包,能收窄就收窄。

所有站点统一放开

写在 nginx.conf 的 http 块里:

nginx 复制代码
http {
    client_max_body_size 100m;

    include /etc/nginx/conf.d/*.conf;
}

之后某个站点想单独收紧,在它的 server 块里再写一次小的值就行。

改完别忘了这一步

bash 复制代码
nginx -t
nginx -s reload

nginx -t 一定要跑,配置写错位置它会直接告诉你哪一行。

还是 413

reload 之后仍然 413,按这个顺序查:

  1. 改的不是那台 Nginx。 链路里可能还有一层:CDN、WAF、SLB,或者前面还架着一台反代。看错误页样式和 Server 响应头,是谁返回的就改谁。这是最常见的原因。
  2. 80 和 443 两个 server 块。 只改了监听 80 的那个,实际流量走的是 443 的块,等于没改。
  3. 后端自己的限制。 Nginx 放行之后请求才轮到应用,PHP 的 post_max_size、upload_max_filesize,Tomcat 的 maxPostSize,Express 的 express.json({ limit }),各自还得对上。
  4. 面板改错地方。 用宝塔的话在「网站 → 设置 → 配置文件」里改,改完在面板里重载,别直接手改 /www/server/nginx/conf/nginx.conf 就以为生效了。

有没有必要把限制调得很大

不建议。真要传大文件,比堆 client_max_body_size 靠谱的做法是:

  • 前端先压缩,或者分片上传 + 断点续传
  • 走对象存储预签名 URL 直传,body 根本不过自己的 Nginx
  • 流式处理,别把整个 body 一次性读进内存

这个阀门存在的意义就是挡恶意大包,图省事设成 0(等于关掉检查),迟早要在别的地方还回来。

附:各层对应的参数

排查的时候对着找就行:

层级 配置
Nginx client_max_body_size 100m;
Apache LimitRequestBody 104857600(单位字节)
PHP upload_max_filesize = 100M、post_max_size = 100M(后者要大于前者)
Spring Boot spring.servlet.multipart.max-file-size、max-request-size
Tomcat maxPostSize、maxSwallowSize
Node/Express express.json({ limit: '100mb' })、multer 的 limits.fileSize
云网关/CDN API Gateway、Cloudflare、WAF、ALB 各有各的请求体上限
相关推荐
蓝速科技1 小时前
仓储盘点移动终端选型与蓝速科技 K10 实战方案
运维·数据库·人工智能·科技·材质
溜达的大象1 小时前
极空间部署Traggo时间追踪工具:Docker安装、标签管理与cpolar远程访问
运维·docker·容器
wjjzhbb1 小时前
Jenkins到ArgoCD——GitOps持续交付实践
运维·缓存·jenkins·argocd
智商网输送线配件1 小时前
流水线全套配件直供化落地的三个实操切入维度
大数据·运维·自动化·智商网·流水线设备配件
硅基手札2 小时前
【linux内核专栏01】Linux 内核心智模型与设计哲学
linux·运维·驱动开发·开源软件
脏脏a2 小时前
极空间部署 Dashlet:Docker 搭建私人导航仪表盘,再配置固定公网访问
运维·docker·容器
中电金信2 小时前
中电金信参编的团体标准《商业银行应用程序接口治理能力要求》正式发布
大数据·运维·人工智能
码完就睡2 小时前
Linux——socket网络编程
linux·运维·网络
道尔柯南2 小时前
【Linux】网络基础概念
linux·运维·网络