Nginx的Rewrite規則與實例

經過Rewrite規則能夠實現規範的URL、根據變量來作URL轉向及選擇配置,用好Rewrite有時起到事半功倍的效果。php

語法css

Nginx的Rewrite相比Apache的要好理解不少,主要使用指令有if、rewrite、set、return、break等,其中rewrite是最關鍵的指令。html

  1. rewrite

    語法: rewrite regex replacement [flag];
    默認值: —
    上下文: server, location, if nginx

    若是指定的正則表達式能匹配URI,此URI將被replacement參數定義的字符串改寫。rewrite指令按其在配置文件中出現的順序執行。flag能夠終止後續指令的執行。若是replacement的字符串以「http://」或「https://」開頭,nginx將結束執行過程,並返回給客戶端一個重定向。
    可選的flag參數能夠是其中之一:
    • last
      中止執行當前這一輪的ngx_http_rewrite_module指令集,而後查找匹配改變後URI的新location;
    • break
      中止執行當前這一輪的ngx_http_rewrite_module指令集;
    • redirect
      在replacement字符串未以「http://」或「https://」開頭時,使用返回狀態碼爲302的臨時重定向;
    • permanent
      返回狀態碼爲301的永久重定向。
    舉例
    server {
        ...
        rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;
        rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra  last;
        return  403;
        ...
    }
    可是當上述指令寫在「/download/」的location中時,應使用標誌break代替last,不然nginx會重複10輪循環,而後返回錯誤500(break和last的區別請參考break):
    location /download/ {
        rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 break;
        rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra  break;
        return  403;
    }
    若是replacement字符串包括新的請求參數,以往的請求參數會添加到新參數後面。若是不但願這樣,在replacement字符串末尾加一個問號「?」,就能夠避免,好比:
    rewrite ^/users/(.*)$ /show?user=$1? last;
    若是正則表達式中包含字符「}」或者「;」,整個表達式應該被包含在單引號或雙引號的引用中。
  2. break

    語法: break;
    默認值: —
    上下文: server, location, if web

    中止處理當前這一輪的ngx_http_rewrite_module指令集。如:
    if ($slow) {
        limit_rate 10k;
        break;
    }
    last和break標記的實現功能相似,但兩者之間細微的差異,使用alias指令時必須用last標記,使用proxy_pass指令時要使用break標記。last標記在本條rewrite規則執行完畢後,會對其所在的server{...}標籤從新發起請求,而break標記則在本條規則匹配完成後終止匹配,不在匹配後邊的規則。所以,通常在根location中(即location / {...})或直接在server標籤中編寫rewrite規則,推薦使用last標記,在非location中(如location /cms/ {...}),則使用break標記。
    對花括號({和})來講,他們既能用在重定向的正則表達式裏,也能用在配置文件裏分割代碼塊,爲了不衝突,正則表達式裏若是帶花括號,應該使用雙引號(或單引號)包圍,如:把/photos/123456重定向到:/path/to/photos/12/1234/123456.png
    rewrite "/photos/([0-9]{2})([0-9]{2})([0-9]{2})" /path/to/photos/$1$2/$1$2$3.png>
  3. if

    語法: if (condition) { ... }
    默認值: —
    上下文: server, location 正則表達式

    用於檢查condition,若是爲真,執行定義在大括號中的rewrite模塊指令。if指令不支持嵌套,不支持多個條件&&和||處理。 
    條件能夠是下列任意一種:
    • 變量名;若是變量值爲空或者是以「0」開始的字符串,則條件爲假;
    • 使用「=」和「!=」運算符比較變量和字符串;
    • 使用「~」(大小寫敏感)和「~*」(大小寫不敏感)運算符匹配變量和正則表達式。正則表達式能夠包含匹配組,匹配結果後續可使用變量$1..$9引用。若是正則表達式中包含字符「}」或者「;」,整個表達式應該被包含在單引號或雙引號的引用中。
    • 使用「-f」和「!-f」運算符檢查文件是否存在;
    • 使用「-d」和「!-d」運算符檢查目錄是否存在;
    • 使用「-e」和「!-e」運算符檢查文件、目錄或符號連接是否存在;
    • 使用「-x」和「!-x」運算符檢查可執行文件;
    如:
    if ($http_user_agent ~ MSIE) {
        rewrite ^(.*)$ /msie/$1 break;
    }
    
    if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
        set $id $1;
    }
    
    if ($request_method = POST) {
        return 405;
    }
    
    if ($slow) {
        limit_rate 10k;
    }
    
    if ($invalid_referer) {
        return 403;
    }
  4. set

    語法: set variable value;
    默認值: —
    上下文: server, location, if 瀏覽器

    爲指定變量variable設置變量值value。value能夠包含文本、變量或者它們的組合,舉例參考下文。
  5. rewrite_log

    語法: rewrite_log on | off;
    默認值:
    rewrite_log off;
    上下文: http, server, location, if 緩存

    開啓或者關閉將ngx_http_rewrite_module模塊指令的處理日誌以notice級別記錄到錯誤日誌中。
  6. uninitialized_variable_warn

    語法: uninitialized_variable_warn on | off;
    默認值:
    uninitialized_variable_warn on;
    上下文: http, server, location, if 服務器

    控制是否記錄變量未初始化的警告到日誌。
  7. return

    語法: return code [text];
    return code URL;
    return URL;
    默認值: —
    上下文: server, location, if cookie

    中止處理並返回指定code給客戶端。狀態碼可使用這些值:20四、400、402-40六、40八、4十、4十一、41三、416及500-504,此外,非標準狀態碼444將以不發送任何Header頭的方式結束連接。

nginx用到的全局變量

$arg_PARAMETER #這個變量包含GET請求中,若是有變量PARAMETER時的值。
$args #這個變量等於請求行中(GET請求)的參數,例如foo=123&bar=blahblah;
$binary_remote_addr #二進制的客戶地址。
$body_bytes_sent #響應時送出的body字節數數量。即便鏈接中斷,這個數據也是精確的。
$content_length #請求頭中的Content-length字段。
$content_type #請求頭中的Content-Type字段。
$cookie_COOKIE #cookie COOKIE變量的值
$document_root #當前請求在root指令中指定的值。
$document_uri #與$uri相同。
$host #請求主機頭字段,不然爲服務器名稱。
$hostname #Set to the machine’s hostname as returned by gethostname
$http_HEADER
$is_args #若是有$args參數,這個變量等於」?」,不然等於」",空值。
$http_user_agent #客戶端agent信息
$http_cookie #客戶端cookie信息
$limit_rate #這個變量能夠限制鏈接速率。
$query_string #與$args相同。
$request_body_file #客戶端請求主體信息的臨時文件名。
$request_method #客戶端請求的動做,一般爲GET或POST。
$remote_addr #客戶端的IP地址。
$remote_port #客戶端的端口。
$remote_user #已經通過Auth Basic Module驗證的用戶名。
$request_completion #若是請求結束,設置爲OK. 當請求未結束或若是該請求不是請求鏈串的最後一個時,爲空(Empty)。
$request_method #GET或POST
$request_filename #當前請求的文件路徑,由root或alias指令與URI請求生成。
$request_uri #包含請求參數的原始URI,不包含主機名,如:」/foo/bar.php?arg=baz」。不能修改。
$scheme #HTTP方法(如http,https)。
$server_protocol #請求使用的協議,一般是HTTP/1.0或HTTP/1.1。
$server_addr #服務器地址,在完成一次系統調用後能夠肯定這個值。
$server_name #服務器名稱。
$server_port #請求到達服務器的端口號。
$uri #不帶請求參數的當前URI,$uri不包含主機名,如」/foo/bar.html」。該值有可能和$request_uri 不一致。$request_uri是瀏覽器發過來的值。該值是rewrite後的值。例如作了internal redirects後。

Rewrite規則實例

  1. 當訪問的文件和目錄不存在時,重定向到某個php文件
    if( !-e $request_filename ) {
    	rewrite ^/(.*)$ index.php last;
    }
  2. 目錄對換 /123456/xxxx ====> /xxxx?id=123456
    rewrite ^/(\d+)/(.+)/  /$2?id=$1 last;
  3. 若是客戶端使用的是IE瀏覽器,則重定向到/ie目錄下
    if( $http_user_agent  ~ MSIE) {
    	rewrite ^(.*)$ /ie/$1 break;
    }
  4. 禁止訪問多個目錄
    location ~ ^/(cron|templates)/ {
    	deny all;
    	break;
    }
  5. 禁止訪問以/data開頭的文件
    location ~ ^/data {
    	deny all;
    }
  6. 禁止訪問以.sh,.flv,.mp3爲文件後綴名的文件
    location ~ .*\.(sh|flv|mp3)$ {
    return 403;
    }
  7. 設置某些類型文件的瀏覽器緩存時間
    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
    	expires 30d;
    }
    location ~ .*\.(js|css)$ {
    expires 1h;
    }

Nginx和Apache的Rewrite規則實例對比

  1. 通常簡單的Nginx和Apache規則的區別不大,基本可以徹底兼容,例如:
    #Apache
    RewriteRule  ^/abc/$   /web/abc.php [L] 
    #Nginx
    rewrite  ^/abc/$  /web/abc.php last ;
    咱們能夠看出來只要把Apache的RewriteRule改成Nginx的rewrite,Apache的[L]改成last 便可。
    若是將Apache的規則改成Nginx規則後,用命令Nginx -t 檢查發現錯誤,則咱們能夠嘗試給條件加上引號,例如:
    rewrite "^/([0-9]{5}).html$"   /x.php?id=$1 last;
  2. Apache和Nginx的Rewrite規則在URL跳轉時有細微區別:
    #Apache
    RewriteRule ^/html/([a-zA-Z]+)/.*$  /$1/  [R=301,L]
    #Nginx
    rewrite ^/html/([a-zA-Z]+)/.*$  http://$host/$1/ premanent;
    咱們能夠看到在Nginx的跳轉中,咱們須要加上http://$host,這是在Nginx中強烈要求的。
  3. 下面是一些Apache和Nginx規則的對應關係
    Apache的RewriteCond對應Nginx的if
    Apache的RewriteRule對應Nginx的rewrite
    Apache的[R]對應Nginx的redirect
    Apache的[P]對應Nginx的last
    Apache的[R,L]對應Nginx的redirect
    Apache的[P,L]對應Nginx的last
    Apache的[PT,L]對應Nginx的last
    例如:容許指定的域名訪問本站,其餘的域名一概轉向www.xiaozhe.com Apache:
    RewriteCond %{HTTP_HOST} !^(.*?)\.aaa\.com$ [NC]
    RewriteCond %{HTTP_HOST} !^localhost$ 
    RewriteCond %{HTTP_HOST} !^192\.168\.0\.(.*?)$
    RewriteRule ^/(.*)$ http://www.xiaozhe.com [R,L]
    Nginx:
    if( $host ~* ^(.*)\.aaa\.com$ )
    {
    set $allowHost ‘1’;
    }
    if( $host ~* ^localhost )
    {
    set $allowHost ‘1’;
    }
    if( $host ~* ^192\.168\.1\.(.*?)$ )
    {
    set $allowHost ‘1’;
    }
    if( $allowHost !~ ‘1’ )
    {
    rewrite ^/(.*)$ http://www.xiaozhe.com redirect ;
    }
相關文章
相關標籤/搜索