nginx之url重寫
1.url重寫模塊(rewrite)
摘要這個模塊允許使用正則表達式重寫uri(需pcre庫),并且可以根據相關變量重定向和選擇不同的配置。如果這個指令在server字段中指定,那么將在被請求的location確定之前執行,如果在指令執行后所選擇的location中有其他的重寫規則,那么它們也被執行。如果在location中執行這個指令產生了新的uri,那么location又一次確定了新的uri。這樣的循環可以最多執行10次,超過以后nginx將返回500錯誤。
break
語法:break?
默認值:none?
使用字段:server, location, if?
完成當前設置的規則,停止執行其他的重寫指令。?
示例:
if?($slow)?{ ?limit_rate?10k; ?break; }
if
語法:if (condition) { … }?
默認值:none?
使用字段:server, location?
注意:在使用if指令之前請查看if is evil page并且盡量考慮用try_files代替。?
判斷一個條件,如果條件成立,則后面的大括號內的語句將執行,相關配置從上級繼承。?
-
可以在判斷語句中指定下列值:
-
一個變量的名稱;不成立的值為:空字符傳”“或者一些用“0”開始的字符串。
-
一個使用=或者!=運算符的比較語句。
-
使用符號~*和~模式匹配的正則表達式:
-
~為區分大小寫的匹配。
-
~*不區分大小寫的匹配(firefox匹配firefox)。
-
!~和!~*意為“不匹配的”。
-
使用-f和!-f檢查一個文件是否存在。
-
使用-d和!-d檢查一個目錄是否存在。
-
使用-e和!-e檢查一個文件,目錄或者軟鏈接是否存在。
-
使用-x和!-x檢查一個文件是否為可執行文件。
正則表達式的一部分可以用圓括號,方便之后按照順序用$1-$9來引用。?
示例配置:
if?($http_user_agent?~?msie)?{ ?rewrite?^(.*)$?/msie/$1?break; } ???????????????????????????????????????????????????????????????????????????? if?($http_cookie?~*?"id=([^;]?+)(?:;|$)"?)?{ ?set?$id?$1; } ???????????????????????????????????????????????????????????????????????????? if?($request_method?=?post?)?{ ?return?405; } ???????????????????????????????????????????????????????????????????????????? if?(!-f?$request_filename)?{ ?break; ?proxy_pass?http://127.0.0.1; } ???????????????????????????????????????????????????????????????????????????? if?($slow)?{ ?limit_rate?10k; } ???????????????????????????????????????????????????????????????????????????? if?($invalid_referer)?{ ?return??403; } ???????????????????????????????????????????????????????????????????????????? if?($args?~?post=140){ ?rewrite?^?http://example.com/?permanent; }
內置變量$invalid_referer用指令valid_referers指定。
return
語法:return code?
默認值:none?
使用字段:server, location, if?
這個指令結束執行配置語句并為客戶端返回狀態代碼,可以使用下列的值:204,400,402-406,408,410, 411, 413, 416與500-504。此外,非標準代碼444將關閉連接并且不發送任何的頭部。
rewrite
語法:rewrite regex replacement flag?
默認值:none?
使用字段:server, location, if?
按照相關的正則表達式與字符串修改uri,指令按照在配置文件中出現的順序執行。?
可以在重寫指令后面添加標記。?
如果替換的字符串以http://開頭,請求將被重定向,并且不再執行多余的rewrite指令。?
尾部的標記(flag)可以是以下的值:
-
last – 完成重寫指令,之后搜索相應的uri或location。
-
break – 完成重寫指令。
-
redirect – 返回302臨時重定向,如果替換字段用http://開頭則被使用。
-
permanent – 返回301永久重定向。
注意如果一個重定向是相對的(沒有主機名部分),nginx將在重定向的過程中使用匹配server_name指令的“host”頭或者server_name指令指定的第一個名稱,如果頭不匹配或不存在,如果沒有設置server_name,將使用本地主機名,如果你總是想讓nginx使用“host”頭,可以在server_name使用“*”通配符(查看http核心模塊中的server_name)。例如:
rewrite?^(/download/.*)/media/(.*)..*$?$1/mp3/$2.mp3?last; rewrite?^(/download/.*)/audio/(.*)..*$?$1/mp3/$2.ra??last; return??403;
但是如果我們將其放入一個名為/download/的location中,則需要將last標記改為break,否則nginx將執行10次循環并返回500錯誤。
location?/download/?{ ?rewrite?^(/download/.*)/media/(.*)..*$?$1/mp3/$2.mp3?break; ?rewrite?^(/download/.*)/audio/(.*)..*$?$1/mp3/$2.ra??break; ?return??403; }
如果替換字段中包含參數,那么其余的請求參數將附加到后面,為了防止附加,可以在最后一個字符后面跟一個問號:
rewrite?^/users/(.*)$?/show?user=$1??last;
注意:大括號({和}),可以同時用在正則表達式和配置塊中,為了防止沖突,正則表達式使用大括號需要用雙引號(或者單引號)。例如要重寫以下的url:
/photos/123456
為:
/path/to/photos/12/1234/123456.png
則使用以下正則表達式(注意引號):
rewrite?"/photos/([0-9]?{2})([0-9]?{2})([0-9]?{2})"?/path/to/photos/$1/$1$2/$1$2$3.png;
如果指定一個“?”在重寫的結尾,nginx將丟棄請求中的參數,即變量$args,當使用$request_uri或$uri&$args時可以在rewrite結尾使用“?”以避免nginx處理兩次參數串。?
在rewrite中使用$request_uri將www.example.com重寫到example.com:
server?{ ??server_name?www.example.com; ??rewrite?^?http://example.com$request_uri??permanent; }
同樣,重寫只對路徑進行操作,而不是參數,如果要重寫一個帶參數的url,可以使用以下代替:
if?($args?^~?post=100){ ?rewrite?^?http://example.com/new-address.html??permanent; }
注意$args變量不會被編譯,與location過程中的uri不同(參考http核心模塊中的location)。
rewrite_log
語法:rewrite_log on | off?
默認值:rewrite_log off?
使用字段:server, location, if?
變量:無?
啟用時將在error log中記錄notice 標記的重寫日志。
set
語法:set variable value?
默認值:none?
使用字段:server, location, if?
指令設置一個變量并為其賦值,其值可以是文本,變量和它們的組合。?
你可以使用set定義一個新的變量,但是不能使用set設置$http_xxx頭部變量的值。
uninitialized_variable_warn
語法:uninitialized_variable_warn on|off?
默認值:uninitialized_variable_warn on?
使用字段:http, server, location, if?
開啟或關閉在未初始化變量中記錄警告日志。?
事實上,rewrite指令在配置文件加載時已經編譯到內部代碼中,在解釋器產生請求時使用。?
這個解釋器是一個簡單的堆棧虛擬機,如下列指令:
location?/download/?{ ?if?($forbidden)?{ ??return??403; ?} ?if?($slow)?{ ??limit_rate?10k; ?} ?rewrite?^/(download/.*)/media/(.*)..*$?/$1/mp3/$2.mp3?break;
將被編譯成以下順序:
variable?$forbidden checking?to?zero recovery?403 completion?of?entire?code variable?$slow checking?to?zero checkings?of?regular?excodession copying?"/" copying?$1 copying?"/mp3/" copying?$2 copying?".mp3" completion?of?regular?excodession completion?of?entire?sequence
注意并沒有關于limit_rate的代碼,因為它沒有提及ngx_http_rewrite_module模塊,“if”塊可以類似”location”指令在配置文件的相同部分同時存在。?
如果$slow為真,對應的if塊將生效,在這個配置中limit_rate的值為10k。?
指令:
rewrite?^/(download/.*)/media/(.*)..*$?/$1/mp3/$2.mp3?break;
如果我們將第一個斜杠括入圓括號,則可以減少執行順序:
rewrite?^(/download/.*)/media/(.*)..*$?$1/mp3/$2.mp3?break;
之后的順序類似如下:
checking?regular?excodession copying?$1 copying?"/mp3/" copying?$2 copying?".mp3" completion?of?regular?excodession completion?of?entire?code
2.簡單案例
注,由于配置文件內容較多,為了讓大家看著方便,我們備份一下配置文件,打開一個新的配置文件。
[root@nginx?~]#?cd?/etc/nginx/ [root@nginx?nginx]#?mv?nginx.conf?nginx.conf.proxy [root@nginx?nginx]#?cp?nginx.conf.bak?nginx.conf [root@nginx?nginx]#?vim?/etc/nginx/nginx.conf server?{ ???listen????80; ???server_name?localhost; ???#charset?koi8-r; ???#access_log?logs/host.access.log?main; ???location?/?{ ?????root??html; ?????index?index.html?index.htm; ?????rewrite?^/bbs/(.*)$?http://192.168.18.201/forum/$1; ???} }
準備forum目錄與測試文件
[root@web1?~]#?cd?/var/www/html/ [root@web1?html]#?ls index.html [root@web1?html]#?mkdir?forum [root@web1?html]#?cd?forum/ [root@web1?forum]#?vim?index.html <h1>forum?page!</h1>
測試一下
好了,下面我們來測試一下rewrite重寫。
3.重新加載一下配置文件
[root@nginx?63]#?service?nginx?reload nginx:?the?configuration?file?/etc/nginx/nginx.conf?syntax?is?ok nginx:?configuration?file?/etc/nginx/nginx.conf?test?is?successful 重新載入?nginx:??????????????????????[確定]
4.測試一下
注,大家可以從圖中看出,status code 302指的是臨時重定向,那就說明我們rewrite重寫配置成功。大家知道302是臨時重定向而301是永久重定向,那么怎么實現永久重定向呢。一般服務器與服務器之間是臨時重定向,服務器內部是永久重定向。下面我們來演示一下永久重定向。
5.配置永久重定向
[root@nginx?nginx]#?vim?/etc/nginx/nginx.conf server?{ ????listen????80; ????server_name?localhost; ????#charset?koi8-r; ????#access_log?logs/host.access.log?main; ????location?/?{ ??????root??html; ??????index?index.html?index.htm; ??????rewrite?^/bbs/(.*)$?/forum/$1; ????} }
準備forum目錄與測試文件
[root@nginx?~]#?cd?/usr/html/ [root@nginx?html]#?ls 50x.html?index.html [root@nginx?html]#?mkdir?forum [root@nginx?html]#?cd?forum/ [root@nginx?forum]#?vim?index.html <h1>192.168.18.208?forum?page</h1>
6.重新加載一下配置文件
[root@nginx?~]#?service?nginx?reload nginx:?the?configuration?file?/etc/nginx/nginx.conf?syntax?is?ok nginx:?configuration?file?/etc/nginx/nginx.conf?test?is?successful 重新載入?nginx:??????????????????????[確定]
7.測試一下
注,大家從圖中可以看到,我們訪問bbs/是直接幫我們跳轉到forum/下,這種本機的跳轉就是永久重定向也叫隱式重定向。