Nginx 如何查看和处理来自上游(upstream)的响应头?
Nginx 上游响应头的查看与改写:$upstream_http_* 变量记日志、proxy_hide_header 隐藏、add_header 透传注意点、proxy_pass_header 解禁,调试方法与 FAQ。
三个核心手段:日志里用 $upstream_http_头名 记录上游返回的任意响应头;proxy_hide_header 屏蔽不想给客户端的;add_header 在反代场景下追加自己的头(注意默认只在部分状态码生效)。
1. 查看:把上游响应头记进日志
调试"上游到底返回了什么",最直接的办法是写日志:
log_format upstream_debug '$remote_addr - $uri → $status '
'up-ct=$upstream_http_content_type '
'up-cache=$upstream_http_cache_control '
'up-time=$upstream_response_time';
access_log /var/log/nginx/upstream.log upstream_debug;
$upstream_http_xxx 变量名规则:头名转小写、连字符变下划线(X-Request-Id → $upstream_http_x_request_id)。
curl -I 发送 HEAD,未必与实际 GET 响应一致;对照 GET 可用 curl -sS -D - -o /dev/null URL。add_header 是追加,若上游已有同名头可能产生重复,替换时需按语义先隐藏。
命令行侧的直接查看:
curl -I https://yoursite/path # 看最终到客户端的头
curl -I http://backend:8080/path # 绕过 Nginx 直连上游对比
2. 隐藏上游的头
上游是应用服务器,常带出不该暴露的信息(X-Powered-By: PHP/8.2、Server 细节):
location / {
proxy_pass http://backend;
proxy_hide_header X-Powered-By;
proxy_hide_header Server;
}
3. 传递被默认屏蔽的头
Nginx 默认不转发上游的部分头(Date、Server、X-Pad、X-Accel-* 等)。确实需要透传时:
proxy_pass_header X-Pad; # 仅示例:确认确有需要才放行
proxy_hide_header 只控制向客户端转发,不能等同于停止处理头部语义。X-Accel-Redirect 会触发内部重定向;若确需改变其处理,应单独评估 proxy_ignore_headers,不能把它当普通诊断头透传。
4. 自己加头(add_header 的坑)
location / {
proxy_pass http://backend;
add_header X-Cache-Status $upstream_cache_status always;
}
两个坑必须知道:
- 默认只对 200/201/204/206/301/302/303/304/307/308 生效——错误响应(4xx/5xx)上不加。要全状态码生效,加
always参数。 - 继承规则:一个层级里只要写了任何
add_header,默认继承行为下父级 add_header 不再继承;新版本提供 add_header_inherit 等控制,需按部署版本核对。
验证响应头时,同时检查客户端收到的值与上游原始值。需要追查缓存或版本差异,可将选定的头字段写进访问日志,再通过观测云 DataKit采集并按该字段查询;只记录必要字段,避免把鉴权令牌或会话信息一并写入。
常见问题(FAQ)
Q:改了上游的头配置但客户端看到的没变?
A:检查是否被 CDN/浏览器缓存了旧响应;以及你的 add_header 是否缺 always,恰好响应是 4xx/5xx 等默认不生效的状态码;304 本来就在默认支持列表中。
Q:上游返回了 Set-Cookie,Nginx 会转发吗?
A:会,Set-Cookie 不在默认屏蔽列表。若要在反代间改写 cookie 域/路径,用 proxy_cookie_domain / proxy_cookie_path。
Q:能按上游响应头做条件处理吗?
A:可以用于读取上游响应后的阶段,但请求重写阶段执行的 if 通常还拿不到响应头;map 也不能让变量提前产生。需要按所用指令阶段设计处理。