Nginx出现400 Request Header Or Cookie Too Large怎么办?Cookie与请求头排查教程

Nginx出现400 Request Header Or Cookie Too Large怎么办?Cookie与请求头排查教程

网站明明没有宕机,大多数访客也能正常打开,偏偏某个用户一访问就看到“400 Request Header Or Cookie Too Large”。更让人困惑的是,换一个浏览器或者打开无痕窗口,页面又恢复正常。

这种故障通常不是上传文件太大,也不一定是后端程序崩溃,而是浏览器发送给服务器的 Cookie 或其他请求头超过了接入层允许的大小。临时扩大 Nginx 缓冲区可以恢复访问,但如果 Cookie 还在持续累积,错误过一段时间还会回来。

本文从快速判断、日志定位、配置调整和根因治理四个层面,完整说明这类 400 错误应该怎么处理。

一、这个400错误到底表示什么

HTTP 请求由请求行、请求头和可选的请求体组成。Cookie、Authorization、Referer、User-Agent 等信息都位于请求头中。

Nginx 会先使用 client_header_buffer_size 读取普通请求头;当请求行或某个请求头字段放不下时,再使用 large_client_header_buffers 提供的大缓冲区。如果请求行仍然无法容纳,Nginx 会返回 414;如果某个请求头字段仍然过大,则会拒绝请求。Nginx 源码内部使用 494 状态处理“请求头过大”,对外错误页通常表现为 400 Request Header Or Cookie Too Large。

这里有两个容易误判的地方:

  1. client_max_body_size 限制的是请求体,主要影响上传文件和较大的 POST 请求,修改它不能解决 Cookie 过大。
  2. large_client_header_buffers 4 16k 不代表单个 Cookie 字段可以使用 64KB。一个请求行或一个请求头字段必须完整放进单个缓冲区,所以这个示例下单个字段的上限仍受 16KB 缓冲区大小约束。

二、先用无痕窗口做一次快速判断

遇到该错误时,先不要急着修改服务器配置。按下面的顺序测试,通常几分钟就能缩小范围。

1. 使用无痕窗口访问

如果普通窗口报错,无痕窗口可以正常访问,优先怀疑该域名下积累了过多 Cookie。无痕窗口没有沿用原会话中的 Cookie,因此请求头会明显变小。

2. 清除当前站点Cookie

只清除故障域名的 Cookie,然后重新登录。如果错误立即消失,说明问题已经基本确认。不过,这只是恢复访问,并没有解释 Cookie 为什么会变大。

3. 比较故障用户和正常用户

如果只有少数长期登录用户遇到问题,常见原因包括:

  • 登录系统重复写入会话 Cookie;
  • OAuth、OIDC 或单点登录流程不断累积状态值;
  • JWT 中放入过多权限、用户资料或业务字段;
  • 同名 Cookie 因 Domain、Path 设置不同而同时发送;
  • 已废弃的 Cookie 没有按原来的 Domain 和 Path 正确删除。

如果所有用户同时报错,则还要检查最近是否上线了新的鉴权头、代理规则,或者 CDN、负载均衡器和 WAF 的限制发生了变化。

三、确认错误是在哪一层产生的

真实网站往往不是浏览器直接连接 Nginx,中间可能还有 CDN、WAF、负载均衡器或 Kubernetes Ingress。任何一层的请求头限制更小,都可能提前拒绝请求。

先观察 Nginx 是否收到故障请求:

sudo tail -f /var/log/nginx/error.log

使用 systemd 管理 Nginx 时,也可以查看服务日志:

sudo journalctl -u nginx --since "30 minutes ago"

重点留意包含以下含义的记录:

  • client sent too long header line
  • client sent too large request

如果浏览器已经报错,但 Nginx 的访问日志和错误日志里完全没有对应请求,说明请求可能在 CDN、WAF 或负载均衡器处就被拦截了。此时只修改源站 Nginx 不会生效,需要继续检查最外层入口的请求头限制。

四、找出究竟是哪一个请求头过大

在 Chrome 或 Edge 中按 F12 打开开发者工具,切换到 Network,刷新故障页面,再打开对应请求的 Headers 面板。重点查看 Request Headers 中的 Cookie 和 Authorization

排查时建议记录三项信息:

  1. 整个请求头的大致大小;
  2. Cookie 字段中出现了哪些 Cookie 名称;
  3. 是否存在同名 Cookie、异常长的 JWT,或者成组重复出现的登录状态字段。

不要只使用 document.cookie 判断 Cookie 大小。带有 HttpOnly 属性的 Cookie 不会暴露给页面 JavaScript,但浏览器仍会把它们发送给服务器。开发者工具中的实际请求头更接近服务器收到的内容。

还可以先发送一个不带历史 Cookie 的干净请求进行对照:

curl -I https://example.com/

如果干净请求正常,而浏览器原会话持续报错,Cookie 膨胀的可能性很高。需要复现完整请求时,可以在开发者工具里复制为 cURL,但注意删除或打码会话令牌后再保存和分享命令。

五、合理调整Nginx请求头缓冲区

确认请求确实到达 Nginx,且业务当前需要较大的 Cookie 或鉴权头后,可以适度调高缓冲区。下面是一组偏保守的示例值,并不是所有网站都应原样照抄:

http { client_header_buffer_size 4k; large_client_header_buffers 4 16k; # 其他配置 }

这两个指令也可以配置在 server 上。若多个虚拟主机共用同一个监听地址,为避免请求在确定虚拟主机前使用了默认服务器的参数,统一配置在 http 层通常更容易管理;如果必须按站点设置,则要同时确认对应监听端口的默认服务器配置。

修改后先检查语法:

sudo nginx -t

确认出现配置测试成功的提示后再平滑重载:

sudo systemctl reload nginx

也可以使用 Nginx 自带的信号命令:

sudo nginx -s reload

重载后重新发送原来的故障请求,并观察访问日志、错误日志和返回状态。不要只测试无痕窗口,因为无痕窗口本来就没有那组超大的 Cookie。

六、为什么不建议直接改成64k或128k

把缓冲区改得很大确实可能立刻消除报错,但这会掩盖 Cookie 无限制增长的问题,也会扩大异常请求对内存和入口资源的消耗。

Nginx 的大请求头缓冲区按需分配,请求进入 keep-alive 状态后会释放,但高并发下大量超大请求头仍然会产生额外开销。更稳妥的做法是:先测量真实请求头大小,留出合理余量,再修复业务侧的增长来源,而不是把限制无限上调。

例如,正常用户的请求头只有 3KB,异常用户却达到 30KB,那么真正应该追查的是这多出来的 27KB,而不是直接把所有入口放宽到 128KB。

七、从业务侧彻底解决Cookie膨胀

1. 不要把完整业务数据塞进Cookie

Cookie 更适合保存短小的会话标识,而不是用户资料、完整权限列表、购物车明细或大段 JSON。服务端可以只保存一个随机会话 ID,再从缓存或数据库读取实际状态。

2. 精简JWT载荷

如果必须使用 JWT,只保留鉴权需要的声明。头像地址、展示名称、完整角色描述等非必要字段不应反复随每个请求发送。还要检查令牌是否被重复包装、重复编码。

3. 检查Domain和Path

设置在 .example.com 下的 Cookie 会发送给多个子域名。若某个 Cookie 只服务于 admin.example.com,就没有必要让它跟随所有子域请求。Path 同样应尽量收窄。

删除 Cookie 时,Domain 和 Path 必须与创建时匹配。只写一个过期的同名 Cookie,却使用了不同 Path,旧 Cookie 可能仍然保留,最终造成多个同名值一起发送。

4. 修复登录流程中的状态累积

某些登录集成会在每次跳转时创建新的 nonce、state 或 correlation Cookie,流程失败后却没有清理。用户重试次数越多,请求头越大。这类问题应在认证回调、失败分支和超时清理逻辑中一起修复。

5. 检查每一层入口限制

如果架构中存在 CDN、WAF、云负载均衡、Ingress 和 Nginx,应记录每一层的请求头限制。最终可用上限由其中最小的一层决定。调整参数后也要从公网入口重新测试,不能只在源站本机使用 curl localhost 验证。

八、常见问题

清除Cookie后恢复了,还需要改Nginx吗?

不一定。先确认这是单个用户的历史残留,还是应用仍在持续写入过大的 Cookie。如果新登录用户使用一段时间后还会复现,应优先修复业务逻辑;若正常业务请求确实略高于现有限制,再适度调整 Nginx。

修改了large_client_header_buffers为什么没有生效?

常见原因有四个:配置文件没有被当前实例加载、修改后没有重载、参数写在了错误的虚拟主机、请求在到达 Nginx 前已被 CDN 或 WAF 拦截。可以结合 nginx -T、错误日志和绕过上游入口的测试逐项确认。

把Cookie拆成多个Cookie能解决吗?

通常不能。浏览器发送请求时,多个 Cookie 往往仍会组合在同一个 Cookie 请求头字段中。真正有效的方法是减少总量、缩小作用域、删除重复项,或者把状态移到服务端。

总结

处理 Nginx 的“400 Request Header Or Cookie Too Large”,最有效的顺序不是先扩大参数,而是先确认问题边界:

  1. 用无痕窗口和清除站点 Cookie 判断是否为用户会话问题;
  2. 查看 Nginx 日志,确认请求有没有到达源站;
  3. 在开发者工具中检查 Cookie、Authorization 和重复字段;
  4. 根据实测大小适度调整 client_header_buffer_size 与 large_client_header_buffers
  5. 回到应用侧清理重复 Cookie、精简 JWT,并检查 Domain、Path 和登录状态累积。

缓冲区调整解决的是“当前请求能不能进来”,Cookie 治理解决的才是“错误会不会再次出现”。两部分一起处理,才能避免同类 400 错误反复发生。

参考资料

  • Nginx 官方文档:Module ngx_http_core_module
  • Nginx 官方文档:Controlling nginx
  • Nginx 官方文档:Beginner’s Guide
  • Nginx 官方源码:ngx_http_request.c、ngx_http_special_response.c
  • RFC 9110:HTTP Semantics
知识库

Docker容器反复重启怎么办?退出码、日志与健康检查排查教程

2026-8-19 18:11:16

知识库

MySQL发生死锁怎么办?死锁日志、事务定位与索引优化教程

2026-8-20 17:21:39