Nginx 返回400错误通常源于自身拦截而非后端,需通过error.log定位具体原因:如请求头过大、URL含非法字符、Host头缺失或协议不匹配,并针对性调整client_header_buffer_size、编码参数、server_name配置等。

nginx 返回 400 错误,多数不是后端问题,而是它在请求进入 upstream 前就主动拒绝了。关键要区分:是 nginx 自己返回的 400,还是它把请求转发给后端后,后端返回的 400。前者查 nginx 配置与日志,后者需同步排查后端服务。
确认是否 nginx 自身拦截
打开 nginx 错误日志(如 /var/log/nginx/error.log),搜索对应时间点的 400 请求记录。若日志中出现类似:
- "client sent too large header" → 请求头超限
- "client intended to send too large body" → 请求体过大
- "invalid host name" 或 "no Host header" → 缺失或非法 Host 头
- "request line is too large" → URL 或请求行过长(含未编码空格、中文、特殊符号)
- "invalid request" 或直接 "400 Bad Request" 无上下文 → 可能是协议不匹配(如 HTTP 请求发到 HTTPS 端口)
常见成因与对应修复
请求头过大(最常见)
尤其当 Cookie 携带大量权限信息、自定义 Header 过长、User-Agent 异常冗长时。nginx 默认仅分配 1KB 缓冲区处理请求头,超出即拒。
- 调整 client_header_buffer_size(建议设为 16k 或 32k)
- 增大 large_client_header_buffers(例如 8 64k,表示最多用 8 个 64KB 缓冲区)
- 若启用 HTTP/2,还需同步配置 http2_max_field_size 和 http2_max_header_size(如 64k / 512k)
URL 或参数含非法字符
例如未编码的空格、中文、花括号 {、竖线 |、尖括号等。RFC 7230 明确限制请求目标(request-target)允许的字符集。
- 前端必须对所有 query 参数执行
encodeURIComponent() - 临时兼容可加 Lua 脚本重写(如用
rewrite_by_lua_block替换非法字符并跳转) - 不建议在后端(如 Tomcat)开放
relaxed-query-chars,存在注入风险
Host 头缺失或格式错误
HTTP/1.1 强制要求 Host 字段。某些旧爬虫、测试工具或异常 SDK 会省略该头。
- 检查客户端是否发送了 Host;可用
curl -v -H "Host:" http://x复现 - Nginx 可设默认 server 拦截空 Host:
server_name _;+return 444;(静默关闭)或return 400; - 避免使用纯 IP 或非法域名(如顶级域名
example.net)作 server_name,改用二级域名
配置验证与生效要点
修改 nginx.conf 后不能直接 reload 就完事:
- 先执行
nginx -t确认语法正确 - 再执行
nginx -s reload(非 restart) - 若涉及 ingress-nginx,需更新 ConfigMap 并触发 rollout(或 helm upgrade)
- 后端容器(如 Spring Boot)也要同步调大 header 限制,例如设置
server.max-http-header-size=262144 - 开启
error_log /var/log/nginx/error.log debug;可捕获更细粒度的拒绝原因(上线后及时关掉)
快速复现与验证方法
在测试环境模拟典型问题,确认修复是否生效:
- 构造超大 Cookie:
curl -H "Cookie: $(printf 'a=%.0s' {1..10000})" http://your.site/ - 发送带空格的 URL:
curl "http://your.site/api?name=hello world" - 省略 Host 头:
curl -H "Host:" http://your.site/ - 发 HTTP 到 HTTPS 端口:
curl http://your.site:443/(应返回明确提示而非 400)











