一 场景1
nginxA作为反向代理,nginxB作为web服务。
其中 nginxA 的日志格式需要打印上游返回的Server头: xes-app : $http_upstream_server
另外A的location配置如下:
location /servertag {
default_type text/plain;
proxy_pass http://servertag;
proxy_set_header Host $host;
# proxy_pass_header Server; # 忽略上游返回的Server的header头
add_header Xes-App $upstream_http_server; #向返回给用户的响应中添加Xes-App的header头
header_filter_by_lua_block {
local cjson = require 'cjson'
local h, err = ngx.resp.get_headers() --查看响应的header信息
ngx.log(ngx.ERR,'-----------',cjson.encode(h))
}
}
测试1:
nginxB配置:
location /servertag {
add_header Server 'zzt-Server'; #在返回给A的响应中添加Server的header头
return 200 "this is a test";
}
当在B的location中加上了一个Server之后,发现B给A发送响应时,会返回两个header头!!!
一个是nginx默认会返回的Server: openresty/1.13.6.1,一个是location中添加的Server: zzt-Server,
当A没有配置 proxy_pass_header Server时,表示nginx A默认忽略B传来的Server头。因此通过ngx.resp.get_headers() 返回的table中没有包含Server字段。
但是用户收到的响应确是:
1 : nginx返回响应时,自动在http报文里加上了当前自己的Server标识。
2 : add_header $upstream_http_server这个指令生效了,即虽然nginx A忽略了Server,但是$upstream_http_server这个变量还是有值的,只是在ngx.get.rep_headers()获取不到Server了。
当A配置了 proxy_pass_header Server时; 表示不对Server的header头忽略。
此时debug日志为:
可见,1 ngx.get.rep_headers()可以获取到Server了,而且header头是将这两个字段作为数组存储的。
2 add_header时,只会取数组中的第一个元素,也就是B 在nginx中额外加的那个Server:zzt-Server并不能返回给用户,也不能记录在日志中。也就是nginx取$upstream_http_server取的是数组中的第一个元素。
二 场景2
后端B换成Tenginx,并且在nginx.conf中加上Server-tag: zzt-Server
则 B返回给A的响应头中,那个默认的Server头已经由openresty/1.13.6.1换成了 zzt-Server,则A再记录日志,返回给用户都是zzt-Server
三 场景3
后端B是golang服务,golang代码里加上Server头,则同样可以满足场景2 的效果。
总结: 1 nginx在发送响应给客户端时,会加上一个默认的Server的header头,哪怕他本身在 location中通过add_header加上了Server,add_header的机制就是在尾部附加,而不是覆盖。
2 $upstream_http_xxx的形式取上游返回的header头时,如果上游同时返回了多个一样字段的header头,这个变量默认取第一个。