Nginx中需用map指令在http块中将$upstream_http_*变量映射为自定义变量才能记录响应头,因$upstream_http_*仅在proxy_pass成功后有效且不可直接用于log_format。

在 Nginx 中,可以通过 $upstream_http_* 变量获取上游(后端)响应头的内容,但要“记录”这些值(比如写入 access log 或传递给其他模块),需先用 map 或 set(配合第三方模块)将其提取为可记录的自定义变量。
使用 map 指令提取响应头为自定义变量
map 是最标准、无需额外模块的方式,适用于将上游响应头映射为可在日志、proxy_set_header 等上下文中使用的变量。
- 必须在
http块中定义,不能放在server或location内 - 源变量只能是 Nginx 内建变量(如
$upstream_http_x_request_id),不能是运行时动态生成的变量 - 目标变量名建议用下划线分隔,避免与内置变量冲突
示例:提取后端返回的 X-Request-ID 和 X-RateLimit-Remaining
http {
map $upstream_http_x_request_id $log_request_id {
default $upstream_http_x_request_id;
"" "-"; # 若响应头不存在或为空,记为 "-"
}
<pre class="brush:php;toolbar:false;">map $upstream_http_x_ratelimit_remaining $log_rate_limit_remaining {
default $upstream_http_x_ratelimit_remaining;
"" "-";
}
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rid="$log_request_id" rl="$log_rate_limit_remaining"';
access_log /var/log/nginx/access.log main;
}
在 location 中通过 proxy_pass 触发 upstream_http_ 变量
$upstream_http_* 变量仅在成功代理到 upstream 后才有效。若请求未进入 upstream(如被 rewrite、return 或内部跳转中断),对应变量为空字符串。
- 确保 location 使用了
proxy_pass,且后端实际返回了目标响应头 - 响应头名称自动转为小写并用下划线替代连字符(如
X-Request-ID→$upstream_http_x_request_id) - 若后端返回多个同名响应头,Nginx 默认只取第一个(遵循 RFC,不支持多值合并)
注意事项与常见问题
直接在 log_format 中使用 $upstream_http_* 不可靠 —— 因为日志格式在请求开始时解析,而 upstream 响应头在响应返回后才可用。必须通过 map 提前声明依赖关系,让 Nginx 知道该变量需延迟求值。
- 变量名拼写必须完全匹配转换规则:
X-Custom-Header→$upstream_http_x_custom_header - 如果后端响应头含空格或特殊字符,Nginx 会原样保留,但日志中可能影响解析(建议后端规范输出)
- 若需修改或添加响应头再透传,用
proxy_hide_header/add_header配合,不影响$upstream_http_*的原始值










