这个问题通常是因为 Nginx 配置中缺少 proxy_set_header 指令,或者自定义头包含下划线被默认丢弃,导致后端服务收不到凭证而拒绝请求。
先说结论:大多数情况是 Nginx 配置中缺少 proxy_set_header 指令,或者自定义头包含下划线被默认丢弃。
- 先确认:查看后端应用日志,确认请求到达时是否缺少特定 Header。
- 先处理:在 Nginx location 块中显式配置 proxy_set_header 传递鉴权头。
- 再验证:使用 curl 携带头信息请求,观察后端响应是否恢复正常。
命令速用版
server {
listen 80;
server_name example.com;
# 若自定义头包含下划线,需在 server 或 http 块开启此选项
underscores_in_headers on;
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 显式传递 Authorization 头,避免被其他配置覆盖
proxy_set_header Authorization $http_authorization;
}
}为什么会这样
Nginx 作为反向代理时,默认会透传大多数请求头,但可能因配置覆盖或包含下划线而丢失。默认情况下,为了安全和规范,Nginx 会忽略包含下划线的请求头,除非显式开启选项。虽然 Authorization 头默认会被透传,但显式声明可避免被其他配置覆盖,具体取决于后端框架的期望和 Nginx 版本行为。
分步处理
1. 检查后端日志:确认后端收到请求时,鉴权头是否存在。如果日志显示头为空或缺失,说明在 Nginx 层丢失。
2. 修改 Nginx 配置:在对应的 server 或 location 块中,添加 proxy_set_header 指令。变量名格式为 $http_头名称(小写,横线变下划线)。
3. 处理下划线问题:如果你的鉴权头名称包含下划线(例如 X_Custom_Token),需要在 http 或 server 块中设置 underscores_in_headers on;。
4. 重载配置:执行 nginx -t 检查语法,然后 nginx -s reload 生效。
怎么验证是否生效
使用 curl 命令模拟请求,verbose 模式可以看到发送的头:
curl -v -H "Authorization: Bearer token123" http://your-nginx-domain/api同时观察后端日志,确认该头值是否已正确接收。如果后端返回 200 而非 403,说明修复成功。
安全与兼容性注意事项
1. CGI 环境冲突:开启 underscores_in_headers 可能导致与 CGI 环境的头名解析冲突,因为 CGI 规范通常将下划线转换为横线。
2. 安全风险:盲目开启 underscores_in_headers 可能引入 HTTP 请求走私风险,建议仅在确需传递含下划线自定义头时开启。
3. 配置层级:underscores_in_headers 指令仅支持 http 或 server 上下文,不可配置在 location 块中。
常见坑
1. 变量名大小写:Nginx 变量 $http_authorization 对应请求头 Authorization,横线在变量名中通常变为下划线。
2. 下划线默认丢弃:RFC 规范建议头名不含下划线,Nginx 默认遵循此建议丢弃含下划线的头,自定义鉴权头容易踩坑。
3. 多个 proxy_set_header:如果在不同层级重复配置,后配置的可能会覆盖先配置的,注意继承关系。
参考来源
- Nginx Official Documentation, ngx_http_proxy_module, proxy_set_header, https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header
- Nginx Official Documentation, ngx_http_core_module, underscores_in_headers, https://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers