一般項目上常用Nginx做負載均衡和靜態資源服務器,本案例中項目上使用Nginx作爲靜態資源服務器出現了很奇怪的現象,我們一起來看看。
“詭異”的現象
部署架構如下圖,Nginx作爲靜態資源服務器監聽8080端口,客戶瀏覽器通過API網關的443端口(就是https)獲取Nginx靜態資源。
現象是用戶瀏覽器訪問API網關的https地址後,API網關將請求SSL解密再請求Nginx 50001端口的/hd-portal路徑,但返回給客戶端的卻是 https://a.com:50001/hd-portal/ !!! 這還是個重定向響應,響應頭裏包含 Location: https://a.com:50001/hd-portal/
,由於API網關並沒有開放這個端口號,所以請求到這裏就無法繼續下去了。
問題分析
筆者是同事拉進線上會議看的這個問題,大家已經琢磨好一會了,我讓同事復現了下現象,也試着調了幾個nginx.conf的參數沒有奏效,趕上快中午了,就讓同事用tcpdump抓下Nginx服務器網絡包,我開始Wireshark分析。(常規定位Nginx的問題有兩個辦法:看access.log判斷問題 和 tcpdump抓包分析確定問題。看access.log沒看出那個50001是誰返回的)
這裏就很明確是Nginx返回的301永久重定向,Nginx使用自己端口號暴露出來做的重定向。到此問題已清晰,只要不讓Nginx把端口號暴露出來就可以了。
問題原因
這得先從Nginx的處理流程說起。
案例中,我們請求的是 https://API網關/hd-portal
,Nginx收到請求發現 /hd-portal
是一個目錄,就會設置響應頭Location
和空的響應體,試圖讓瀏覽器以目錄方式訪問資源。而瀏覽器收到響應後,解析響應頭髮現 Location
響應頭確定要重定向,就開始跳轉 https://API網關/hd-portal/
。
以上是正確合理的情況,不合理的點在於:Nginx爲啥把自己端口號暴露出來了?
經過查詢了Nginx官方文檔,發現了三個有聯繫的配置項,分別貼圖出來:
這三個配置分別是 absolute_redirect / server_name_in_redirect / port_in_redirect,以下簡要說明下三者作用:
- absolute_redirect:啓用時表示絕對路徑重定向,默認on啓用
- server_name_in_redirect: 啓用時表示使用Nginx的server_name配置替換重定向路徑,默認off禁用
- port_in_redirect:啓動時表示重定向時替換重定向的端口號,默認on啓用
- 這三個配置關係中,如果absolute_redirect配置off,則後兩個配置失效。
解決方案
至此,可以有兩種解決方案,根據實際情況任選其一即可:
- absolute_redirect配置
off
(禁用絕對路徑跳轉,相當於自動識別目錄) - port_in_redirect配置
off
(禁止替換重定向端口號)
這兩個方案的配置位置可以是http / server / localtion
塊,作用範圍也是根據配置位置決定的。
至於本案例中,由於多個項目使用同一個server,就在location塊中添加了 port_in_redirect: off;
解決了問題。
總結
本文試圖從問題現象到分析與解決方案的提出讓讀者能對Nginx的301重定向做到心中有數,相信讀者看完本文再出現類似的問題解決起來肯定更輕鬆愉快!
我是Hellxz,如果本文對您有所幫助,請點個贊再走唄!~