這裏不討論rewrite中的配置, 不討論nginx的其他配置
rewrite: 使用nginx提供的全局變量或自定義變量,結合正則表達式和標誌位實現url重寫以及重定向。
rewrite只能放在配置文件的server{ }
,location{}
,if{}
中,並且只能對域名後面(或者叫路徑, 不包含請求參數(query string
))的字符串起作用。
例如: http://www.domain.com/a/b/index.html?id=1&page=2
只對 /a/b/index.html 重寫。
如果想對域名或請求參數(
query string
)起作用,可使用全局變量匹配,也可以使用proxy_pass
反向代理。
- 語法:rewrite regex replacement [flag];
- 默認值:無
- 作用域:server,location,if
如果一個URI
匹配指定的正則表達式regex
,URI
就按照replacement
重寫。
rewrite
按配置文件中出現的順序執行,flags標誌可以停止繼續處理。
如果replacement
以 "http://" 或 "https://" 開始,將不再繼續處理,這個重定向將返回給客戶端。
rewrite指令執行順序
- 執行
server
塊的rewrite
指令(這裏的塊指的是server關鍵字後{}包圍的區域,其它xx塊類似) - 執行
location
匹配 - 執行選定的
location
中的rewrite
指令
如果其中某步URI被重寫,則重新循環執行1-3,直到找到真實存在的文件;循環超過10次,則返回500 Internal Server Error
錯誤。
rewrite
和location
功能有點像,都能實現跳轉,區別在於:
rewrite
是在同一域名內更改獲取資源的路徑location
是對一類路徑做控制訪問或反向代理,可以proxy_pass
到其他機器。
很多情況下rewrite也會寫在location裏.
rewrite實例:
server {
...
rewrite ^(/download/.*)/media/(.*)..*$ $1/mp3/$2.mp3 last;
rewrite ^(/download/.*)/audio/(.*)..*$ $1/mp3/$2.ra last;
return 403;
...
}
如果這些rewrite放到 “/download/” location 如下所示, 那麼應使用break
而不是last
, 使用last
將循環10次匹配,然後返回 500錯誤:
location /download/ {
rewrite ^(/download/.*)/media/(.*)..*$ $1/mp3/$2.mp3 break;
rewrite ^(/download/.*)/audio/(.*)..*$ $1/mp3/$2.ra break;
return 403;
}
對於重寫後的 URL
(replacement
)包含原請求的請求參數
(query string
),即原URL
的?
後的內容。如果不想帶原請求的參數 ,可以在replacement
後加一個問號
。如下,我們加了一個自定義的參數user=$1
, 然後在結尾處放了一個問號?
, 把原請的參數去掉:
rewrite ^/users/(.*)$ /show?user=$1? last;
flag 標誌位
flag
可以是如下參數:
- last 停止處理後續
rewrite
指令集,然後對當前重寫的新URI
在rewrite
指令集上重新查找。相當於Apache
的[L]
標記 - break 停止處理後續
rewrite
指令集,並不再重新查找, 但是當前location
內剩餘非rewrite
語句和location
外的的非rewrite
語句可以執行。 - redirect 如果
replacement
不是以"http://" 或 "https://" 開頭,返回302臨時重定向,地址欄會顯示跳轉後的地址 - permant 返回301永久重定向,地址欄會顯示跳轉後的地址
在rewrite
中last
和 break
的區別:
last
一般寫在server
和if
段中,而break
一般使用在location
段中last
不終止重寫後的url匹配,即新的url
會再從server
走一遍匹配流程,而break
終止重寫後的匹配break
和last
都能組織繼續執行後面的rewrite
指令
最終完整的重定向URL包括請求scheme
(http://, https:// 等), 請求的server_name_in_redirect
和 port_in_redirec
三部分 ,說白了也就是http協議 域名 端口三部分組成。
if指令與全局變量
if指令
語法:if(condition){...}
默認值:無
作用域:server
, location
對給定的條件condition
進行判斷。如果爲真,大括號內的rewrite
指令將被執行。
if條件(conditon
)可以是如下任何內容:
- 當表達式只是一個變量時,如果值爲空或任何以0開頭的字符串都會當做 (bool)false
- 直接比較變量和內容時,使用
=
或!=
~
正則表達式匹配,~*
不區分大小寫的匹配,!~
區分大小寫的不匹配. 如果這個正則表達式中包含}
,
;
則整個表達式需要用雙引號" 或 單引號' 包圍-f
和!-f
用來判斷是否存在文件-d
和!-d
用來判斷是否存在目錄-e
和!-e
用來判斷是否存在文件或目錄-x
和!-x
用來判斷文件是否可執行
e.g:
if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /msie/$1 break;
} //如果UA包含"MSIE",rewrite請求到/msid/目錄下
if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
set $id $1;
} //如果cookie匹配正則,設置變量$id等於正則引用部分
if ($request_method = POST) {
return 405;
} //如果提交方法爲POST,則返回狀態405(Method not allowed)。return不能返回301,302
if ($slow) {
limit_rate 10k;
} //限速,$slow可以通過 set 指令設置
if (!-f $request_filename){
break;
proxy_pass http://127.0.0.1;
} //如果請求的文件名不存在,則反向代理到localhost 。這裏的break會停止rewrite檢查
if ($args ~ post=140){
rewrite ^ http://example.com/ permanent;
} //如果query string中包含"post=140",永久重定向到example.com
location ~* \.(gif|jpg|png|swf|flv)$ {
valid_referers none blocked www.jefflei.com www.leizhenfang.com;
if ($invalid_referer) {
return 404;
} //防盜鏈
}
全局變量
- $args : 請求參數,同$query_string
- $content_length : 請求頭中的Content-length字段。
- $content_type : 請求頭中的Content-Type字段。
- $document_root : 當前請求在root指令中指定的值。
- $host : 請求主機頭字段,否則爲服務器名稱。
- $http_user_agent : 客戶端agent信息
- $http_cookie : 客戶端cookie信息
- $limit_rate : 限制連接速率。
- $request_method : 客戶端請求的動作,通常爲GET或POST。
- $remote_addr : 客戶端的IP地址。
- $remote_port : 客戶端的端口。
- $remote_user : 已經經過Auth Basic Module驗證的用戶名。
- $request_filename : 當前請求的文件路徑,由root或alias指令與URI請求生成。
- $scheme : HTTP方法(如http,https)。
- $server_protocol : 請求使用的協議,通常是HTTP/1.0或HTTP/1.1。
- $server_addr : 服務器地址,在完成一次系統調用後可以確定這個值。
- $server_name : 服務器名稱。
- $server_port : 服務器的端口號。
- $request_uri : 包含請求參數的原始URI,不包含主機名,如:”/foo/bar.php?arg=baz”。
- $uri : 不包含主機名和請求參數的當前URI,如”/foo/bar.html”。
- $document_uri : 與$uri相同。
正則匹配
- . : 匹配除換行符以外的任意字符
- ? : 重複0次或1次
- + : 重複1次或更多次
- * : 重複0次或更多次
- {n} : 重複n次
- {n,} : 重複n次或更多次
- \d :匹配數字
- ^ : 匹配字符串的開始
- $ : 匹配字符串的介紹
- [c] : 匹配單個字符c
- [a-zA-Z0-9] : 匹配a-z小寫字母,A-Z大寫字母, 數字0-9 中的任意一個
- (jpg|png) : 匹配字符串 jpg 或 png , 括號表示分組
小括號()
之間匹配的內容,可以在後面通過$1來引用,$2表示的是前面第二個()裏的內容
rewrite '^/images/([a-z]{2})/([a-z0-9]{5})/(.*)\.(png|jpg|gif)$' /data?file=$3.$4;
# 注意不能在上面這條規則後面加上“last”參數,否則下面的set指令不會執行
set $file_name_without_ext $3;
set $file_ext $4;
對形如 /images/ef/202103/test.png 的請求,重寫到 /data?file=test.png
rewrite規則中如果要忽略大小寫, 可以使用 (?i)
這個與用"/"開始結尾的javascript/php等語言的reg pattern使用/i是不同的.
rewrite ^(.*)_(middle|small)(\.(?i)(jpg|jpeg|png|gif))$ /thumb_fixed.php break;
這個規則把 xxx_middle.jpg, xxx_middle.JPG, xxx_small.png, xxx_small.PNG 這樣的圖片地址進行了重寫