nginx處理redirect location端口丟失的問題

前言

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重寫的形式帶上端口。

相關文章
相關標籤/搜索