問題引入
最近開發同事反饋在服務器內讀取到的url在一個特定的地方多了一個/,本來應該是http://example.domain.url/servername/appname/dosomething這樣的地址,在服務器上收到的地址為http://example.domain.url/servername//appname/dosomething,影響了后續的應用處理,
在應用服務器的前一層恰好是NGINX反向代理,網路硬體截取域名,將http://servername/appname/dosomething丟給NGINX進行分發,NGINX通過配置upstream負載均衡,再通過proxy_pass拼接新的url,通過proxy_set_header重定義請求頭,而在做轉發的時候正是將servername替換為實際的服務器IP:PORT,這個操作看起來是影響服務的關鍵節點,
原先配置
# upstream part
upstream servername {
server 192.168.100.1:8888;
server 192.168.100.2:8888;
check interval=5000 rise=1 fall=3 timeout=4000;
}
..........
# proxy_pass part
location /servername/ {
proxy_pass http://servername/appname/;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Request-Context http://$host:$server_port/servername/;
proxy_set_header X-Real-IP $remote_addr;
}
懷疑是proxy
location后帶/不帶/,proxy_pass后帶/不帶/,查資料發現不同位置會影響url轉義結果,那么會不會遵循完整替換原則呢?
1
location /pass/ {
proxy_pass http://localhost:8080;
}
# http://localhost:8080/pass/xxx
}
2
location /pass/ {
proxy_pass http://localhost:8080/;
}
# http://localhost:8080/xxx
}
3
location /pass {
proxy_pass http://localhost:8080;
}
# http://localhost:8080/xxx
}
4
location /pass {
proxy_pass http://localhost:8080/;
}
# http://localhost:8080//xxx
}
這四種情況看起來是有三種結果,不過為了驗證可以再進階一下:
5
location /pass/ {
proxy_pass http://localhost:8080/app;
}
# http://localhost:8080/appxxx
}
6
location /pass/ {
proxy_pass http://localhost:8080/app/;
}
# http://localhost:8080/app/xxx
}
7
location /pass {
proxy_pass http://localhost:8080/app;
}
# http://localhost:8080/app/xxx
}
8
location /pass {
proxy_pass http://localhost:8080/app/;
}
# http://localhost:8080/app//xxx
}
可以看到2 3 6 7的方式是正確的,location部分結尾帶/則proxy_pass部分結尾帶/,location部分結尾不帶/則proxy_pass部分結尾不帶/,完整的遵從同義替換,因此本身我們的組態檔在這邊書寫是沒錯的,
懷疑是應用
那么是不是應用本身的問題導致的呢?
假想會不會是應用bug或者配置的問題導致應用接收的url錯誤,其實nginx轉發并沒有問題,
為了判斷該問題,只能抓包,
在服務器安裝了wireshark,過濾掉非http包,發現攜帶的url確實是http://example.domain.url/servername//appname/dosomething這樣的,問題還是在nginx上面,
是proxy_set_header嗎?
洗掉proxy_set_header里的/變成了
# upstream part
upstream servername {
server 192.168.100.1:8888;
server 192.168.100.1:8888;
check interval=5000 rise=1 fall=3 timeout=4000;
}
..........
# proxy_pass part
location /servername/ {
proxy_pass http://servername/appname/;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Request-Context http://$host:$server_port/servername;
# 注意servername后面的/去掉了
proxy_set_header X-Real-IP $remote_addr;
}
再進行抓包,url變成http://example.domain.url/servername/appname/dosomething正常了,看來罪魁禍首找到了,
為什么是proxy_set_header
proxy_set_header用來重新定義或添加欄位傳遞給代理服務器的請求頭,在沒有定義proxy_set_header時會繼承之前定義的值,也就是如果前道網路設備修改了請求頭以后,nginx不作修改的話會原樣轉發請求頭;但是也可以修改里面的文本和變數或者是它們的組合,
那么X-Forwarded-Request-Context修改的是請求頭的哪一部分就是現在要了解的重點了,這個引數確實過于冷門,翻遍全網只有在esri的問答網站有這樣一個回答(回答地址)
X-Forwarded-Url-Base: web adaptor context
X-Forwarded-Request-Context: this appears to be the same as the web context url setting
webAdaptorID: web adaptor id
X-Forwarded-For: an external ip
這里就是設定web url的,并且目前看到只有arcgis的應用讀取這個設定,看來確實會影響web url,但是為什么不遵循跟proxy_pass一樣的替換原則,這個只有該模塊的開發者才能知道了,注意proxy_set_header 來自內置模塊ngx_http_proxy_module,不屬于第三方模塊,
那么不如來引申一下,深入了解一下proxy_set_header模塊,這個后續會單獨寫一篇博客,
另一種處理//問題
在查找這個問題的時候,我看到了另一個NGINX處理//的方式,地址
前端參考css,js時如果寫的…/…/之類的參考方式,那么在訪問鏈接中加入多個斜杠會導致參考失敗.
可以通過nginx對多個斜杠進行處理
如訪問 public//view//a//test.html 重定向到 public/view/a/test.html
merge_slashes off;
rewrite (.*)//(.*) $1/$2 permanent;
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/292309.html
標籤:其他
