Nginx的rewrite(地址重定向)剖析


1、rewrite語法:

  指令語法:rewrite regex replacement[flag];

  默認值:none

  應用位置:server、location、if

  rewrite是實現URL重定向的重要指令,他根據regex(正則表達式)來匹配內容跳轉到replacement,結尾是flag標記

  簡單的小例子:

1
rewrite ^/(.*) http: //www .baidu.com/ permanent;      # 匹配成功后跳轉到百度,執行永久301跳轉

  常用正則表達式:

字符 描述
\ 將后面接着的字符標記為一個特殊字符或者一個原義字符或一個向后引用
^ 匹配輸入字符串的起始位置
$ 匹配輸入字符串的結束位置
* 匹配前面的字符零次或者多次
+ 匹配前面字符串一次或者多次
? 匹配前面字符串的零次或者一次
. 匹配除“\n”之外的所有單個字符
(pattern) 匹配括號內的pattern

 

  rewrite 最后一項flag參數:

標記符號 說明
last 本條規則匹配完成后繼續向下匹配新的location URI規則
break 本條規則匹配完成后終止,不在匹配任何規則
redirect 返回302臨時重定向
permanent 返回301永久重定向

 

2、應用場景:

  •  調整用戶瀏覽的URL,看起來規范
  • 為了讓搜索引擎收錄網站內容,讓用戶體驗更好
  • 網站更換新域名后
  • 根據特殊的變量、目錄、客戶端信息進行跳轉

3、常用301跳轉:

  之前我們通過用起別名的方式做到了不同地址訪問同一個虛擬主機的資源,現在我們可以用一個更好的方式做到這一點,那就是跳轉的方法

  還是用www.brian.com虛擬主機為例子,修改配置文件brian.conf:

復制代碼
[root@Nginx www_date]# cat brian.conf 
    server {                          # 添加個server區塊做跳轉
    listen     80;
    server_name  brian.com;
    rewrite ^/(.*) http://www.brian.com/$1 permanent;
    }
    server {
        listen       80;
        server_name  www.brian.com;
        location / {
            root   html/brian;
            index  index.html index.htm;
        }
        access_log logs/brian.log main gzip buffer=128k flush=5s; 
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
 }
復制代碼

   檢查語法:

[root@Nginx conf]# 
[root@Nginx conf]# ../sbin/nginx -t
nginx: the configuration file /opt/nginx//conf/nginx.conf syntax is ok
nginx: configuration file /opt/nginx//conf/nginx.conf test is successful

  平滑重啟:

1
[root@Nginx conf] # ../sbin/nginx -s reload

  windows測試效果:

4、域名跳轉:

  我們不僅可以做相同虛擬主機的資源域名跳轉,也能做不同虛擬主機的域名跳轉,我們下面就跳轉下當訪問brian.com域名的時候跳轉到www.baidu.com的頁面:

  修改www.brian.com虛擬主機的brian.conf配置文件:

復制代碼
[root@Nginx www_date]# cat brian.conf 
    server {
        listen       80;
        server_name  brian.com;
        location / {
            root   html/brian;
            index  index.html index.htm;
        }
    if ( $http_host ~* "^(.*)") {
        set $domain $1;
        rewrite ^(.*) http://www.baidu.com break;
    }
        access_log logs/brian.log main gzip buffer=128k flush=5s; 
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
 }
復制代碼

  windows測試:(訪問brian.com 跳轉到了www.baidu.com)

 

 

加一篇新的解釋:

rewrite模塊即ngx_http_rewrite_module模塊,主要功能是改寫請求URI,是Nginx默認安裝的模塊。rewrite模塊會根據PCRE正則匹配重寫URI,然后發起內部跳轉再匹配location,或者直接做30x重定向返回客戶端。

rewrite指令的工作原理

rewrite模塊的指令有break, if, return, rewrite, set等。rewrite指令所執行的順序如下:

  • 首先在server上下文中依照順序執行rewrite模塊指令;
  • 如果server中行了rewrite重寫,那么以新URI發起內部跳轉,直接匹配location,不會再執行server里的rewrite指令,然后
    • 新URI直接匹配location
    • 如果匹配上某個location,那么其中的rewrite模塊指令同樣依照順序執行
    • 如果再次導致URI的rewrite,那么再一次進行內部跳轉去匹配location,但跳轉的總次數不能超過10次

rewrite

基本語法: rewrite regex replacement [flag];
上下文:server, location, if

regex是PCRE 風格的,如果regex匹配URI,那么URI就會被替換成replacement,replacement 就是新的URI。如果rewrite同一個上下文中有多個這樣的正則,匹配會依照rewrite指令出現的順序先后依次進行下去,匹配到一個之后並不會終止,而是繼續往下匹配,直到返回最后一個匹配上的為止。如果想要中止繼續往下匹配,可以使用第三個參數flag。

如果新URI字符中有關於協議的任何東西,比如http://或者https://等,進一步的處理就終止了,直接返回客戶端302。

如果返回的是30x,那么瀏覽器根據這個狀態碼和Location響應頭再發起一次請求,然后才能得到想要的響應結果。但是,如果不是返回30x狀態碼,那么跳轉就是內部的,瀏覽器不做跳轉就能得到相應。

注意:regex直接就是正則表達式,不要再前面添加~符號

flag 參數可以有以下的一些值:

last

如果有last參數,那么停止處理任何rewrite相關的指令,立即用替換后的新URI開始下一輪的location匹配

break

停止處理任何rewrite的相關指令,就如同break 指令本身一樣。

last的break的相同點在於,立即停止執行所有當前上下文的rewrite模塊指令;不同點在於last參數接着用新的URI馬上搜尋新的location,而break不會搜尋新的location,直接用這個新的URI來處理請求,這樣能避免重復rewite。因此,在server上下文中使用last,而在location上下文中使用break

redirect

replacement 如果不包含協議,仍然是一個新的的URI,那么就用新的URI匹配的location去處理請求,不會返回30x跳轉。但是redirect參數可以讓這種情況也返回30x(默認302)狀態碼,就像新的URI包含http://和https://等一樣。這樣的話,瀏覽器看到302,就會再發起一次請求,真正返回響應結果的就是這第二個請求。

permanent

和redirect參數一樣,只不過直接返回301永久重定向

雖說URI有了新的,但是要拼接成完整的URL還需要當前請求的scheme,以及由server_name_in_redirectport_in_redirect指令決定的HOST和PORT.

還有一個比較有意思的應用,就是如果replacement中包含請求參數,那么默認情況下舊URI中的請求參數也會拼接在replacement后面作為新的URI,如果不想這么做,可以在replacement的最后面加上?。

舉例說明:

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

這樣的新URI還是 /show?user=xxx

但如果不加問號:

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

得到的新URI就是/show?user=$1&xxx=xxx。其中xxx=xxx是舊URI所帶的請求參數。

rewrite的例子

在server中使用的情況:

server {
    ...
    rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last; rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra last; return 403; #沒有匹配上,那就返回403咯 ... }

注意,在server中使用rewrite ,我們使用的flag是last,但是在location中,我們卻只能用break:

location /download/ { rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 break; rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra break; return 403; } 

如果在location的rewrite也使用last,便會再次以新的URI重新發起內部重定向,再次進行location匹配,而新的URI中極有可能和舊的URI一樣再次匹配到相同location中,這樣死循環發生了。當循環到第10次時,Nginx會終止這樣無意義的循環,並返回500錯誤。這點需要特別的注意。

break

基本語法:break;
上下文:server, location, if

停止處理任何rewrite的相關指令。如果出現在location里面,那么所有后面的rewrite模塊指令都不會再執行,也不發起內部重定向,而是直接用新的URI進一步處理請求。

server {
  # 訪問 /last.html 的時候,頁面內容重寫到 /index.html 中,並繼續后面的location匹配,瀏覽器地址欄URL地址不變
  rewrite /last.html /index.html last;

  # 訪問 /break.html 的時候,頁面內容重寫到 /index.html 中,並停止后續的匹配,瀏覽器地址欄URL地址不變;
  rewrite /break.html /index.html break;

  # 訪問 /redirect.html 的時候,頁面直接302定向到 /index.html中,瀏覽器地址URL跳為index.html
  rewrite /redirect.html /index.html redirect;

  # 訪問 /permanent.html 的時候,頁面直接301定向到 /index.html中,瀏覽器地址URL跳為index.html
  rewrite /permanent.html /index.html permanent;

  # 把 /html/*.html => /post/*.html ,301定向
  rewrite ^/html/(.+?).html$ /post/$1.html permanent;

  # 把 /search/key => /search.html?keyword=key
  rewrite ^/search\/([^\/]+?)(\/|$) /search.html?keyword=$1 permanent;
  
  # 把當前域名的請求,跳轉到新域名上,域名變化但路徑不變
  rewrite ^/(.*) http://www.jd.com/$1 permanent;
  }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM