Nginx 重寫規則(rewrite rule)

這裏不討論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匹配指定的正則表達式regexURI就按照replacement重寫。

rewrite按配置文件中出現的順序執行,flags標誌可以停止繼續處理。

如果replacement以 "http://" 或 "https://" 開始,將不再繼續處理,這個重定向將返回給客戶端。

rewrite指令執行順序

  1. 執行server塊的rewrite指令(這裏的塊指的是server關鍵字後{}包圍的區域,其它xx塊類似)
  2. 執行location匹配
  3. 執行選定的location中的rewrite指令

如果其中某步URI被重寫,則重新循環執行1-3,直到找到真實存在的文件;循環超過10次,則返回500 Internal Server Error錯誤。

rewritelocation功能有點像,都能實現跳轉,區別在於:

  • 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;
 }

對於重寫後的 URLreplacement)包含原請求的請求參數(query string),即原URL?後的內容。如果不想帶原請求的參數 ,可以在replacement後加一個問號。如下,我們加了一個自定義的參數user=$1, 然後在結尾處放了一個問號?, 把原請的參數去掉:

rewrite ^/users/(.*)$ /show?user=$1? last;

flag 標誌位

flag可以是如下參數:

  • last 停止處理後續rewrite指令集,然後對當前重寫的新URIrewrite指令集上重新查找。相當於Apache[L]標記
  • break 停止處理後續rewrite指令集,並不再重新查找, 但是當前location內剩餘非rewrite語句和location外的的非rewrite語句可以執行。
  • redirect 如果replacement不是以"http://" 或 "https://" 開頭,返回302臨時重定向,地址欄會顯示跳轉後的地址
  • permant 返回301永久重定向,地址欄會顯示跳轉後的地址

rewritelastbreak的區別:

  • last一般寫在serverif段中,而break一般使用在location段中
  • last不終止重寫後的url匹配,即新的url會再從server走一遍匹配流程,而break終止重寫後的匹配
  • breaklast都能組織繼續執行後面的rewrite指令

最終完整的重定向URL包括請求scheme(http://, https:// 等), 請求的server_name_in_redirectport_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 這樣的圖片地址進行了重寫

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章