413错误可能由请求头过大引发,而非仅body超限;当client_header_buffer_size或large_client_header_buffers不足时,nginx在解析header阶段即拒绝请求,根本未进入body校验。

413 错误不是只由 client_max_body_size 引起的;当上传接口报 413,但你确认 body 大小没超、client_max_body_size 也设对了,大概率是请求头(headers)触发了另一道拦截——large_client_header_buffers 或 client_header_buffer_size 不足。
为什么改了 client_max_body_size 还报 413?
因为 Nginx 在解析请求时分两步:先读 header,再读 body。如果 header 太大(比如带长 JWT、多层代理头、超长 Cookie 或嵌套的 X-Forwarded-For),Nginx 在第一步就拒绝了请求,根本不会走到 body 校验那步。此时 error log 里通常没有 “too large body”,而是:
-
400 Bad Request或静默断连 - 日志中出现
client sent too large request或request header or cookie too large - 甚至什么都没记——因为解析失败太早,连日志都来不及打全
client_header_buffer_size 和 large_client_header_buffers 怎么配
这两个参数必须一起看,不能只调一个:
-
client_header_buffer_size是每个请求的初始 header 缓冲区,默认1k。够用就不用动;如果业务常用长 token(如 2KB 的 JWT),建议提到2k或4k -
large_client_header_buffers是备用缓冲池,语法是large_client_header_buffers 4 8k,意思是“最多分配 4 个 8KB 缓冲区”。注意:单个 header 必须能放进**一个** buffer 里,不能跨 buffer 拼接。所以真正上限是8k,不是4 × 8k - 典型安全值:
client_header_buffer_size 2k;+large_client_header_buffers 8 16k;→ 单请求 header 最大支持 16KB - 别盲目设成
16 64k:内存开销线性增长,且多数攻击场景下反而更易被耗尽资源
location 块里也要检查 client_max_body_size 是否被覆盖
很多人在 http 块设了 client_max_body_size 50m,结果上传仍 413。原因往往是:
- 实际请求走的是某个
server块,而该块里显式写了client_max_body_size 1m,覆盖了 http 层配置 - 或者用了反向代理,请求匹配到了
location /,但该 location 没写client_max_body_size,于是继承 server 默认值(可能仍是 1m) - 正确做法:在真正处理上传的
location里显式设,例如location /api/upload { client_max_body_size 50m; ... } - 顺手加一句
proxy_buffering off;(可选):避免大 body 被缓存两次,尤其配合client_body_buffer_size 1m时更稳
验证是否真生效,别信 reload 成功提示
reload 成功 ≠ 配置加载成功,更不等于请求走对了路径:
- 用
curl -v -H "X-Long-Header: $(printf 'a%.0s' {1..12000})" http://host/health测试 header 限制(12KB) - 上传略超原限制的文件(如原限 1M,传 1.1MB 的 zip),观察是否还 413
- 查
/var/log/nginx/error.log,搜client intended to send too large body(body 超限)或client sent too large request(header 超限) - 在
location块里临时加return 200 "header size: $request_length";,看响应里是否包含完整 header 长度(需开启log_format自定义字段才准)
最常被忽略的点:header 和 body 限制是两条独立通路,改完一个不等于另一个自动跟上;而且 proxy 场景下,后端服务(如 PHP、Node.js)自身的 header/body 限制也得同步放宽,否则 Nginx 放行了,后端照样拒收。











