網絡訪問關係圖以下, PC瀏覽器須要訪問到Tomcat的Web應用.nginx
由於網絡隔離, PC機所在的環境訪問不了Nginx2, 因此加了一層Nginx1的網絡代理. Ngnix1的簡要配置以下:web
server{ listen 8888; server_name 10.254.209.65; location / { proxy_pass http://10.254.213.149:80; } }
而後Nginx2代理了tomcat應用, 簡要配置以下:瀏覽器
upstream tom { server ip:port; } server { listen 80; server_name 10.254.213.149; location /admin { proxy_pass http://tom/admin; } }
在PC瀏覽器上輸入10.254.209.65:8888/admin/就能夠正常顯示tomcat的web頁面, 而輸入10.254.209.65:8888/admin 時就404, 後者比前者少了一個斜槓「/」而已.tomcat
在PC瀏覽器輸入10.254.209.65:8888/admin 時, 發現地址會莫名其妙地重定向爲 10.254.209.65/admin/服務器
重定向以後的地址有2處明顯變化: 一是端口8888變成了80(默認不顯示) ; 二是admin後面追加上了斜槓「/」.網絡
彷佛問題的根源仍是斜槓「/」, 那就先從它入手.curl
Nginx不會自動追加斜槓「/」, 其配置文件裏也沒有顯示去追加「/」, 因而開始懷疑到Tomcat.url
切到Nginx2所在主機下, 不走代理, 經過curl直接訪問Tomcat應用:spa
curl -I http://tom/admin代理
顯示信息以下
HTTP/1.1 302
Location: http://tom/admin/Transfer-Encoding: chunked
Date: Sun, 30 Dec 2018 13:24:35 GMT
確實發生了302重定向, 而且地址追加上了斜槓「/」.
想了想應用代碼應該不會無端幹這種事, 難道是Tomcat本身乾的?
因而去看了一下Tomcat的access日誌, 確實有一個302. 而後去網上查了一下資料, 大體就是說當Tomcat的應用帶有contentPath的時候, 好比這裏的/admin, 那麼客戶端訪問時, 若是直接請求/admin的話, Tomcat就會自動重定向去追加斜槓變成/admin/.
到此, 咱們彷佛已經知道如何去解決問題了, 只要在Nginx2的proxy_pass地址後面顯示加個「/」就好了, 以下:
proxy_pass http://tom/admin/;
這樣/admin請求在Nginx2處轉發時就會帶上「/」, 而後Tomcat收到請求後就不會再重定向了.
驗證一下, 在PC上輸入10.254.209.65:8888/admin 確實訪問正常了.
看似問題是解決了, 可是重定向端口號從8888變成了80尚未查明, 裏面必定有坑.
重定向不一樣於服務器內部轉發, 重定向的指令是服務器發給客戶端的, 固然應該使用客戶端輸入的IP和PORT.
繼續分析, 這時產生了一個錯覺: Tomcat在重定時拿到的端口號不對, 它只拿到了最近一個Nginx的端口, 即Nginx2的端口80, 而拿不到Nginx1的8888.
爲何說是錯覺呢, 由於Tomcat其實根本不會去拿什麼端口號,它只會拿當前Http請求的Head裏面的Host信息.
爲何用Nginx這麼久, 不多碰到這種端口問題, 由於通常用的端口是80, 而Nginx代理時Host的取值默認是$host, 至關於$host:80, 因此也就不會出問題.
在一些特殊場景出現非80端口時, 若是隻有一層Nginx代理還好說, 能夠在代理時設置Head轉發後的Host值, 把端口帶上, 以下
proxy_set_header Host $host:$server_port;
可是對於當前問題場景, 有2層Nginx代理, Nginx2沒法直接拿到Nginx1的端口信息, 那怎麼辦呢?
目前能想到的方法, 就是在代理/admin下設置Host時, 把配置端口寫死, 以下:
proxy_set_header Host $host:8888;
這樣當Tomcat重定向時就沒有問題了, 不過你得先知道客戶端請求的端口是8888, 當其變化後也須要跟着同步.