nginx關(guān)于add_header的坑及解決
一、add_header指令不會去重
nginx做反向代理時,如果后端返回的response中已經(jīng)有該header頭,則通過add_header后會返回給客戶端兩個同樣的header頭。
場景1:
nginxA作為反向代理,nginxB作為web服務(wù)。我是拿的openresty 1.13.6.2測試的,本質(zhì)上是一樣,其中A是openresty 1.15.8.1嗎,B是openresty 1.13.6.2。
其中 nginxA 的日志格式里配置了打印上游返回的Server頭: xes-app : $http_upstream_server
測試1: add_header指令對重復(fù)指令的處理。
A的location配置如下:
server { listen 80; server_name test.header.com; access_log /home/nginx/logs/test.header.com_access.log main; error_log /home/nginx/logs/error.log debug; location / { set $upstream 'test.header.com'; proxy_pass http://$upstream; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
nginxB的配置如下:
server{ listen 80; server_name test.header.com; access_log /home/nginx/logs/test.header.com.log main; index index.php index.html index.htm; location / { add_header Server 'MytestB'; return 200 "this is test header from zlear"; } }
這種配置下,B返回給A響應(yīng)時會加上一個'Server: MytestB'的header。
- 直接訪問B:
- 訪問A,A反向代理到B:
此時只有一個Server的 header,而且是A的openresty 版本標(biāo)識。
測試1結(jié)果:
1 : nginx返回響應(yīng)時,會自動在http報文里加上了當(dāng)前自己的Server標(biāo)識。
2: 單純的配置add_header指令時,如果response中已經(jīng)有該header了,則會重復(fù)添加。
3: 通過反向代理NginxA之后,A會隱藏掉B返回給自己的Server Header頭,并將自己的Server標(biāo)識返回給客戶端。
測試2: proxy_hide_header與proxy_pass_header指令對add_header有影響嗎?
說明:proxy_hide_header : nginx在做反向代理時,為了隱藏上游服務(wù)器的信息,不會將上游的Server返回給客戶端。
語法: proxy_hide_header field;
默認值: —
上下文: http, server, location
nginx默認不會將“Date”、“Server”、“X-Pad”,和“X-Accel-...”響應(yīng)頭發(fā)送給客戶端。proxy_hide_header指令則可以設(shè)置額外的響應(yīng)頭,這些響應(yīng)頭也不會發(fā)送給客戶端。
proxy_pass_header: 和proxy_hide_header相反,如果希望允許傳遞某些響應(yīng)頭給客戶端,可以使用proxy_pass_header指令。
例如: proxy_pass_header Server; 則告訴nginx服務(wù)傳遞上游的Server頭,而不是將它自己放在響應(yīng)中。
- 在測試1的基礎(chǔ)上,在A上加上proxy_pass_header指令:
server { listen 80; server_name test.header.com; access_log /home/nginx/logs/test.header.com_access.log main; error_log /home/nginx/logs/error.log debug; location / { set $upstream 'test.header.com'; proxy_pass http://$upstream; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass_header Server; } }
通過A訪問B如下:
此時和測試1中的直接訪問B結(jié)果一樣。
- 在測試1的基礎(chǔ)上,在NginxB上添加指令add_header MytestB MytestB;
server{ listen 80; server_name test.header.com; access_log /home/nginx/logs/test.header.com.log main; index index.php index.html index.htm; location / { add_header Server 'MytestB'; add_header MytestB 'MytestB'; return 200 "this is test header from zlear"; } }
測試2結(jié)果:
1、 nginx默認會隱藏上游返回的Server 的header頭,但是可以通過pass_header_header Server;來取消該限制,此時用戶會收到B返回的兩個header頭。
2、對于其他的非默認屏蔽的header頭,則NginxA會原樣透傳給用戶。如果想屏蔽某個header頭,可以通過proxy_hide_header指令。
二、add_header指令會覆蓋
如果在http、server、location都配置了add_header指令之后,返回給用戶的是什么呢?
例如如下配置:
server { listen 80; server_name test.header.com; access_log /home/nginx/logs/test.header.com_access.log main; error_log /home/nginx/logs/error.log debug; add_header Test1 AAA; location / { set $upstream 'test.header.com'; proxy_pass http://$upstream; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; add_header Test2 BBB; } }
這樣的配置下,會返回給用戶什么header呢?
答案是只會以location的為準,在server里配置的Test1并不生效。同理在http段配置的更加不會生效。 優(yōu)先級location > server > http。
三、擴展
1、 ngx.resp.get_headers()
對Nginx A測試 ngx.resp.get_headers
-- header.lua local json = require('cjson') local h, err = ngx.resp.get_headers() ngx.log(ngx.ERR, '-------resp header:-------', json.encode(h))
結(jié)果如下:
2020/08/06 10:07:02 [error] 5616#0: *15175 [lua] header.lua:9: -------resp header:-------{"connection":"keep-alive","content-type":"application\/octet-stream","mytestb":"MytestB","content-length":"34"} while reading response header from upstream, client: 127.0.0.1, server: test.header.com, request: "GET http://test.header.com/aaa HTTP/1.1", upstream: "http://xxxx:80/aaa", host: "test.header.com"
接著在A中加上配置項: proxy_pass_header Server;
再次測試結(jié)果:
2020/08/06 10:04:58 [error] 5564#0: *14655 [lua] header.lua:9: -------resp header:-------{"content-type":"application\/octet-stream","server":["openresty\/1.13.6.2","MytestB"],"connection":"keep-alive","mytestb":"MytestB","content-length":"34"} while reading response header from upstream, client: 127.0.0.1, server: test.header.com, request: "GET http://test.header.com/aaa HTTP/1.1", upstream: "http://xxx:80/aaa", host: "test.header.com"
結(jié)論
1、ngx.resp.get_headers() 只能獲取到proxy_hide_header外的header頭,如果想獲取到默認被屏蔽掉的那些header,需要用proxy_pass_header來添加。
2、 默認情況下,此api獲取到的header是一個key-value形式,但是如果upstream返回了兩個同樣的header,lua會用數(shù)組的形式存儲。
2、 Server-tag會覆蓋Server header頭
后端B換成Tenginx,并且在nginx.conf中加上Server-tag: MytestB
則 B返回給A的響應(yīng)頭中,那個默認的Server頭已經(jīng)由openresty/1.13.6.1換成了 MytestB,則A再記錄日志,返回給用戶都是zzt-Server
3、 代碼自定義Server的header頭會覆蓋nginx自帶的
后端B是golang服務(wù),golang代碼里加上Server頭,則同樣可以滿足2中的效果。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
單臺web服務(wù)器如何盡可能的提高網(wǎng)站性能
一個網(wǎng)站,對于個人或小公司來說,前期直接上集群的開銷是比較大的,那么采用單臺服務(wù)器如何才能盡可能的提高網(wǎng)站效率呢?2014-06-06Nginx?ingress?controller高可用的實現(xiàn)
本文主要介紹了Nginx?ingress?controller高可用的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-06-06詳解Nginx proxy_pass的一個/斜杠引發(fā)的血案
這篇文章主要介紹了詳解Nginx proxy_pass的一個/斜杠引發(fā)的血案,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11nginx centos 服務(wù)開機啟動設(shè)置實例詳解
這篇文章主要介紹了nginx centos 服務(wù)開機啟動設(shè)置實例詳解的相關(guān)資料,這里對服務(wù)開機啟動做了詳細的步驟介紹,需要的朋友可以參考下2016-11-11