nginx 默认静默丢弃含下划线的请求头字段,需在 http 或 server 块中启用 underscores_inheaders on 才能接收并传递;启用后可通过 $http* 变量引用,再用 proxy_set_header 透传给后端;推荐改用短横线命名以兼容所有中间件。

Nginx 默认会静默丢弃请求头中带下划线(_)的字段,比如 auth_token、x_user_id、file_last_modified,这不是 bug,而是出于历史安全考虑——为避免与 CGI 环境变量命名冲突(CGI 会把 - 和 _ 都转成 _),nginx 默认禁用下划线字段。只要请求经过 nginx(无论反向代理、Ingress 还是 CDN),这些 header 就不会到达后端。
要让 nginx 接收并传递带下划线的 header,核心操作是启用 underscores_in_headers 指令。
在 nginx 配置中开启 underscores_in_headers
该指令必须放在 http 块或 server 块中(不能放在 location 块里),生效后 nginx 才会接受含 _ 的请求头字段名:
http {
# 全局启用:影响所有 server
underscores_in_headers on;
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 其他 proxy_set_header...
}
}
}
或者只在特定 server 启用:
server {
listen 80;
server_name api.example.com;
underscores_in_headers on; # 仅对该 server 生效
location / {
proxy_pass http://127.0.0.1:8000;
# ...
}
}
⚠️ 注意事项:
- 修改后必须执行
nginx -t && nginx -s reload才能生效; -
underscores_in_headers on只控制接收请求头(request headers),不影响响应头(response headers); - 子
server块不自动继承父级http块中的设置,需显式声明; - 若使用 K8s Ingress 或云厂商负载均衡(如阿里云 SLB、腾讯云 CLB),需确认其底层 nginx 版本 ≥ 1.11.4 且已开启该配置,否则仍会丢弃。
后端读取时注意变量名转换
开启后,nginx 内部将下划线 header 转为小写加下划线的变量名,供 $http_* 引用:
- 请求头
X_User_ID→ 可用$http_x_user_id - 请求头
Auth_Token→ 可用$http_auth_token - 请求头
bundle_name→ 可用$http_bundle_name
若需透传给后端,记得在 proxy_set_header 中显式设置:
proxy_set_header Auth-Token $http_auth_token; # 转成标准格式再传 # 或直接透传原始名(前提是后端支持) proxy_set_header X-User-ID $http_x_user_id;
更推荐的做法:改用短横线命名
虽然能开 underscores_in_headers,但长期看更稳妥的方式是统一改用短横线(-):
-
auth_token→auth-token -
x_merchant_id→x-merchant-id -
file_last_modified→file-last-modified
这样无需改 nginx 配置,天然兼容所有中间件(CDN、WAF、Ingress、Apache),也符合 HTTP/1.1 字段命名惯例(RFC 7230 明确推荐使用连字符)。
不复杂但容易忽略











