nginx有時候並不像apache那樣智能,對於redirect location的處理尤其慘淡,幾乎只能用戶手工處理非標準端口的問題。html
好比由於種種緣由,nginx並不能監聽在80端口,或者外部經過NAT方式將請求丟給nginx,外部地址並非標準http(s)端口,此時nginx並不能美好的處理這些重定向。發生重定向的時候會丟失端口。nginx
好比如下兩種參考範例:git
#反向代理 listen 81 default_server; set $TOMCAT_HOME /var/lib/tomcat7; location / { root $TOMCAT_HOME/webapps/ROOT; proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
# 訪問/data的時候會自動加上/成爲/data/ listen 81 default_server; location /data { root /var/data; }
瀏覽器請求的時候會發現只要發生重定向,端口號就會丟失,致使瀏覽器訪問到錯誤的端口。web
分別對這兩種狀況給出解決方案。apache
這個很容易搞定,那一堆proxy_set_header
不知道什麼時候在網上流傳開來的,幾乎國內外文檔無一例外都是這個鳥樣子。後來我發現gitlab-ce
這個用非標準端口訪問是沒有問題的,我看了一下gitlab-ce的nginx配置,發現是這麼配置的:ubuntu
proxy_set_header Host $http_host;
我又發現nginx軟件包釋放出的配置文件(from ppa: NGINX Stable),發現裏面實際上是帶有一個參考文件/etc/nginx/proxy_params
瀏覽器
proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;
這裏面寫的也是 proxy_set_header Host $http_host;
,因而乎直接include,搞定tomcat
location / { root $TOMCAT_HOME/webapps/ROOT; proxy_pass http://127.0.0.1:8080/; include proxy_params; }
沒這個文件就把這些內容手工敲到location
配置段下。bash
再細看官方文檔,其實也說起了:app
An unchanged 「Host」 request header field can be passed like this: proxy_set_header Host $http_host;
這個比較棘手,好比$document_root
存在data/index.html
文件,可是訪問的時候最後沒加/
,nginx會自動給你帶上/
,返回一個301重定向(這個行爲和apache一致),可是比較扯的地方在於,若是nginx監聽的是非標準端口,這個301返回的Location
沒有端口號,致使瀏覽器請求出錯。用curl能夠很明顯的看到這一點:
$ curl -v mydomain:81/data * Hostname was NOT found in DNS cache * Trying *.*.*.*... * Connected to mydomain (*.*.*.*) port 81 (#0) > GET /test HTTP/1.1 > User-Agent: curl/7.35.0 > Host: mydomain:81 > Accept: */* > < HTTP/1.1 301 Moved Permanently * Server nginx is not blacklisted < Server: nginx < Date: Wed, 18 Nov 2015 07:39:03 GMT < Content-Type: text/html < Content-Length: 178 < Connection: keep-alive < Location: http://mydomain/data/ < <html> <head><title>301 Moved Permanently</title></head> <body bgcolor="white"> <center><h1>301 Moved Permanently</h1></center> <hr><center>nginx</center> </body> </html> * Connection #0 to host mydomain left intact
能夠很明顯的看到Location
沒有端口號了,這個重定向又和反向代理不同。因而遍尋google,最終在stackoverflow的問答中找到了解決方案:
if (-d $request_filename) { rewrite [^/]$ $scheme://$http_host$uri/ permanent; }
經過手工對URL重寫的形式帶上端口。