nginx高階篇rewrite

不太聪明的大鹅發表於2024-03-22

url重寫技術
更改請求的url
http://www.yuchaoit.cn/
自動跳轉到
new.yuchaoit.cn


比如早期的京東官網,域名叫做 
360buy.com

企業就進行域名修改。
jd.com


老使用者他又不知道你改名了,
360buy.com 看到網頁無響應,以為京東掛了。。不用這個網站了,京東跑路了,以後用拼多多吧。。


京東就是用rewrite技術,實現,讓舊域名的請求,自動重定向(永久重定向)
到新域名


老客戶瀏覽器發出請求 www.360buy.com 瀏覽器自動的又發出一個新請求,跳轉到新請求域名上 www.jd.com(會發現瀏覽器的url,也自動更換為了新的域名)


rewrite還有哪些功能,
1.實現URL的永久重定向
(1.整個域名的全部替換 2.比如給http跳轉到https)


在你學習rewrite之前,要先掌握它基本的一些邏輯引數,如何用

3.這個功能就得透過ngx_http_rewrite_module 這個模組實現
該模組提供了多個指令功能

break     # 中斷配置
if        # 請求判斷
set      # 設定變數
return  # 返回值


rewrite  # 對使用者請求URL重寫
官網
https://nginx.org/en/docs/http/ngx_http_rewrite_module.html

該ngx_http_rewrite_module模組用於使用 PCRE 正規表示式更改請求 URI、返回重定向和條件選擇配置。

指令語法(if)

1.if語句,用於條件判斷,根據判斷結果的不同,執行不同的動作,if寫在server{}或者location{}標籤裡。

if (匹配條件) {
    執行動作
}

匹配規則

if的匹配條件可以是如下任意一種。


1.if語句,用於條件判斷,根據判斷結果的不同,執行不同的動作,if寫在server{}或者location{}標籤裡。


# 比如針對使用者的請求客戶端判斷,或者針對使用者的ip地址判斷
# 基於nginx的內建變數就可以提取出這些資訊。。
if (匹配條件) {
    執行動作
}

匹配條件
	- nginx內建變數
	- 使用nginx的if提供的條件判斷符號,等於不等於,....


server {

    # 客戶端完全匹配到
    listen 22555;
    server_name localhost;
    root html;
    charset utf-8;

    location  /test-if {

        # 客戶端型別完全匹配到 huawei
        if ($http_user_agent = huawei){

            echo "agent is huawei";
        }

        # 客戶端型別區分大小寫
        # 你這裡的正則符號,就是一個完全的字元 ,區分大小寫的字串
        # Iphone ,你只能傳入 Iphone才行
        # 基於正則匹配,你得寫入正則符號。
        if ($http_user_agent ~ Iphone) {
            echo "agent is Iphone";
        }

        # 客戶端型別不區分大小寫
        if ($http_user_agent ~* Chrome) {
            echo "agent is Chrome";
        }

        # 如果請求方法不是GET就提示 ”只能用GET方法,你這個爛玩家“
        if ($request_method != GET) {
            echo "必須是GET方法,你這個爛玩家";
        }

        # 如果是IE瀏覽器,直接提示 "不支援IE,請下載Chrome瀏覽器"
        # 不區分大小寫的正則匹配
        if ($http_user_agent ~* IE){
            echo "不支援IE,請下載Chrome瀏覽器";
        }

        # 如果上面沒有任何匹配,執行如下語句
        echo  "if規則沒有匹配到";
        echo "agent is  >>>>>>     $http_user_agent";
        echo "request_method is  >>>>>>>>  $request_method";
    }

}

測試實際用法

# http預設的請求方式,如瀏覽器訪問,如curl命令訪問,都是GET方法,獲取資源的意思
[root@master-61 ~]#curl 10.0.0.8:22555/test-if
if規則沒有匹配到
agent is  >>>>>>     curl/7.29.0
request_method is  >>>>>>>>  GET

測試完全匹配,基於useragent精確匹配到字串huawei

[root@master-61 ~]## curl -A 表示傳輸 user-agent的字串資訊
[root@master-61 ~]#
[root@master-61 ~]#
[root@master-61 ~]#curl 10.0.0.8:22555/test-if
if規則沒有匹配到
agent is  >>>>>>     curl/7.29.0
request_method is  >>>>>>>>  GET
[root@master-61 ~]#
[root@master-61 ~]#
[root@master-61 ~]#curl -A 'huawei-mate40' 10.0.0.8:22555/test-if
if規則沒有匹配到
agent is  >>>>>>     huawei-mate40
request_method is  >>>>>>>>  GET
[root@master-61 ~]#curl -A 'Huawei' 10.0.0.8:22555/test-if
if規則沒有匹配到
agent is  >>>>>>     Huawei
request_method is  >>>>>>>>  GET
[root@master-61 ~]#curl -A 'huawei' 10.0.0.8:22555/test-if
agent is huawei

測試區分大小寫的正則匹配
重點就在於
如下表示式,你看懂即可

if ($http_user_agnet ~ 正規表示式 ) {
程式碼塊;
}

[root@master-61 ~]##測試區分大小的 Iphone
[root@master-61 ~]#
[root@master-61 ~]#curl -A 'iphone' 10.0.0.8:22555/test-if
if規則沒有匹配到
agent is  >>>>>>     iphone
request_method is  >>>>>>>>  GET
[root@master-61 ~]#
[root@master-61 ~]#
[root@master-61 ~]#curl -A 'Iphone' 10.0.0.8:22555/test-if
agent is Iphone
[root@master-61 ~]#curl -A 'IPhone' 10.0.0.8:22555/test-if
if規則沒有匹配到
agent is  >>>>>>     IPhone
request_method is  >>>>>>>>  GET

測試不區分大小寫的正則匹配

[root@master-61 ~]#
[root@master-61 ~]#curl -A 'windows xxxxx chrome xxxxx' 10.0.0.8:22555/test-if
agent is Chrome
[root@master-61 ~]#
[root@master-61 ~]#
[root@master-61 ~]#curl -A 'windows xxxxx CHroME xxxxx' 10.0.0.8:22555/test-if
agent is Chrome
[root@master-61 ~]#
[root@master-61 ~]#curl -A 'windows xxxxx CHroMxE xxxxx' 10.0.0.8:22555/test-if
if規則沒有匹配到
agent is  >>>>>>     windows xxxxx CHroMxE xxxxx
request_method is  >>>>>>>>  GET
[root@master-61 ~]#
[root@master-61 ~]#
[root@master-61 ~]## 看懂扣 3 不懂 4
[root@master-61 ~]## 不區分大小寫的正則匹配

測試指定請求方法

[root@master-61 ~]## 如果你給 10.0.0.8:22555/test-if 傳送的請求方式不是GET,就會進入如下的 if條件區域
[root@master-61 ~]#
[root@master-61 ~]#curl -X POST 10.0.0.8:22555/test-if 
必須是GET方法,你這個爛玩家
[root@master-61 ~]#
[root@master-61 ~]#
[root@master-61 ~]#curl -X PUT  10.0.0.8:22555/test-if 
必須是GET方法,你這個爛玩家
[root@master-61 ~]#curl -X DELETE  10.0.0.8:22555/test-if 
必須是GET方法,你這個爛玩家


測試IE瀏覽器

1.測試方法,基於curl去測
[root@master-61 ~]#curl -A 'windows xxxx   IE11xxxxxx' 10.0.0.8:22555/test-if 
不支援IE,請下載Chrome瀏覽器


2. 直接使用ie瀏覽器去測

return指令

return用於返回如狀態碼
或者重寫url
或者響應狀態碼、以及文字等

return之後的命令不會再執行。


具體return用法

[root@web-9 /etc/nginx/conf.d]#cat return.conf 
server {

    listen 22666;
    server_name _;
    root html;

    # 精確匹配,客戶端只訪問了網頁根目錄
    location  = / {
        echo "welcome to chaoge linux course.";
    }

    location /test-return {

            # 客戶端完全匹配
            if ($http_user_agent = huawei){
              return 200 "agent is  $http_user_agent \n";
            }

            # 限制必須是GET方法
            if ($request_method != GET){

              return 405 "必須是GET方法!其他方法不允許\n";
            }

            # 如果是IE瀏覽器,就重定向
            if ($http_user_agent ~* IE){
              return 301 http://yuchaoit.cn/cai.jpg;
            }

                        # 沒有if條件匹配到
            return 404 "sorry, nothing ....\n";
     }

        # 預設匹配,如果沒有匹配到任意內容,跳轉到首頁 jd.com就是這個做法
        location / {
      return 301 http://yuchaoit.cn/cai.jpg;
        }

        location /ji {
            return 500 "雞你太美\n";
        }

}


實踐return的執行
精準匹配location

[root@master-61 ~]#
[root@master-61 ~]#curl 10.0.0.8:22666/
welcome to chaoge linux course.

沒有匹配到任何location,進入預設的location

並且結合了301的用法

瀏覽器測試
訪問的是 10.0.0.8:22666/xixixixi
但是實現了301永久跳轉,url會跟著變化
跳轉到了 新url ,。http://yuchaoit.cn/cai.jpg

訪問具體的location規則

[root@master-61 ~]#curl -I 10.0.0.8:22666/ji
HTTP/1.1 500 Internal Server Error
Server: nginx/1.19.0
Date: Wed, 25 May 2022 03:08:47 GMT
Content-Type: application/octet-stream
Content-Length: 13
Connection: keep-alive

[root@master-61 ~]#
[root@master-61 ~]#
[root@master-61 ~]#curl -I 10.0.0.8:22666/ji/xixixixixi
HTTP/1.1 500 Internal Server Error
Server: nginx/1.19.0
Date: Wed, 25 May 2022 03:09:05 GMT
Content-Type: application/octet-stream
Content-Length: 13
Connection: keep-alive

[root@master-61 ~]#curl  10.0.0.8:22666/ji/xixixixixi
雞你太美
[root@master-61 ~]#curl  10.0.0.8:22666/ji/xixixixix/haHAHAH
雞你太美

基於location匹配的綜合用法

[root@master-61 ~]#curl -I  10.0.0.8:22666/test-return/xixixixixixi
HTTP/1.1 405 Not Allowed
Server: nginx/1.19.0
Date: Wed, 25 May 2022 03:12:51 GMT
Content-Type: application/octet-stream
Content-Length: 43
Connection: keep-alive

[root@master-61 ~]#curl   10.0.0.8:22666/test-return/xixixixixixi
sorry, nothing ....
[root@master-61 ~]#
[root@master-61 ~]#
[root@master-61 ~]#
[root@master-61 ~]#
[root@master-61 ~]#
[root@master-61 ~]#curl  -A 'huawei'  10.0.0.8:22666/test-return/xixixixixi
agent is  huawei 
[root@master-61 ~]#curl  -I  -A 'huawei'  10.0.0.8:22666/test-return/xixixixixi 
HTTP/1.1 200 OK
Server: nginx/1.19.0
Date: Wed, 25 May 2022 03:13:42 GMT
Content-Type: application/octet-stream
Content-Length: 18
Connection: keep-alive

[root@master-61 ~]#
[root@master-61 ~]#
[root@master-61 ~]## 看懂這些綜合用法的,扣 1 不懂2
[root@master-61 ~]#
[root@master-61 ~]#
[root@master-61 ~]#curl -X POST 10.0.0.8:22666/test-return/xxxxxxxxxxxxxxxxxxx
必須是GET方法!其他方法不允許
[root@master-61 ~]#
[root@master-61 ~]#curl -I  -X POST 10.0.0.8:22666/test-return/xxxxxxxxxxxxxxxxxxx
HTTP/1.1 405 Not Allowed
Server: nginx/1.19.0
Date: Wed, 25 May 2022 03:15:18 GMT
Content-Type: application/octet-stream
Content-Length: 43
Connection: keep-alive

set指令

set就是用於設定一個nginx變數,這個值可以是文字、變數或者其組合。

set可以用於設定server{}  location{}  if{}

set 變數名 變數值;
用於在nginx中設定變數,然後可以在配置檔案中呼叫該變數


# 測試用法如下

server {

    listen 22777;
    server_name _;
    root html;
    
    set $my_url http://yuchaoit.cn/data/cai.jpg;

    location /test-set {
        return 301 $my_url;
    }

}

# 測試執行
訪問10.0.0.8:22777/test-set/

break指令

語法

break用於終止所在區域的後續指令,且只針對ngx_http_rewrite_module提供的模組指令;
也就是咱們目前所學的這幾個rewrite相關的指令,在break後面不會執行了。

break可以用於
server{}
location{}
if{}

break是專門用於終止,rewrite的其他指令的執行的

rewrite這個url重寫模組,支援如下幾個關鍵字
break, if, return, rewrite, and set
這些關鍵字都可以在server{} location中定義

break的作用是,nginx的程式碼,執行帶break之後,就會停止後續的

if, return, rewrite,  set指令的執行。。

結合rewrite實際用法,來看break的其他用法

準備測試配置檔案

server {

        listen 22888;
        server_name _;
        root html;

        location / {

                set $my_website yuchaoit.cn;
                echo "welcome to my website:" $my_website;
                break;

                set $my_name yuchao;
                echo "my name is" $my_name;

        }

}

重點,rewrite實際用法

官網
https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite


句法:    rewrite regex replacement [flag];
預設:    —
語境:    server, location,if

指令語法

1. rewrite指令可以基於使用者的請求url,再透過正規表示式的匹配情況,進行地址重寫;
2. rewrite指令可以寫多條,按照順序依次執行;
3. rewrite指令可以根據flag標記進行進一步處理(last、break、redirect、permanent)

flag引數解釋

可選flag引數可以是以下之一:

last
停止處理當前的 ngx_http_rewrite_module指令集,向下匹配新的locaiton URI規則;

break
ngx_http_rewrite_module與break指令一樣, 停止處理當前的指令集 ;

redirect(公司的域名臨時更換)
返回帶有 302 程式碼的臨時重定向;
如果替換字串不以“ http://”、“ https://”或“ $scheme”開頭,則使用該字串;
瀏覽器將顯示跳轉後的url地址,且瀏覽器不會做dns快取記錄;

permanent(公司域名永久更換,老域名還在執行)
返回帶有 301 程式碼的永久重定向。
瀏覽器會記錄跳轉後的dns快取,瀏覽器顯示跳轉後的url。

工作應用場景

1.設定redirect、permanent引數,瀏覽器都會更改為跳轉後的url,是由伺服器返回新的URL,客戶端對這個URL重新發起了請求。

2.設定last和break引數,瀏覽器依然顯示原本的URL,由於伺服器內部完成跳轉。

3.last和break區別
last在標記完本次規則匹配完成後,對其所在的server{}標籤重新發起修改後的URL請求,再次匹配location{}。

break是在本條規則匹配完畢後,終止匹配,不再匹配後面的location{};

檢視301的實際用法(permanent)
permanent和301永久重定向

HTTP協議規範裡,301是永久重定向、302是臨時重定向。

301,域名永久更新,更換域名

laoliulinux.cc  舊域名
↓
linux0224.com   新域名


在rewrite中使用 rewrite /  http://linux0224.com permanent;
自動識別為301狀態,永久跳轉

舊域名配置檔案,基於域名的虛擬主機了,做好域名匹配

[root@web-8 /opt/nginx-1-19-0/conf/extra]#cat laoliu.conf 
server {
    listen 80;
    server_name laoliulinux.cc;
    location / {
        root /laoliu/;
        index index.html;
        # rewrite regex   新域名  引數
        #  rewrite regex(提取域名後面的引數)   新域名  引數
        # 簡單的域名跳轉用法
        rewrite /  http://linux0224.com permanent;
    }
}

# 建立資料檔案
[root@web-8 /opt/nginx-1-19-0/conf/extra]#mkdir /laoliu
[root@web-8 /opt/nginx-1-19-0/conf/extra]#
[root@web-8 /opt/nginx-1-19-0/conf/extra]#echo 'laoliu 666666666 old   domain' > /laoliu/index.html 

新域名配置檔案 這個新域名,應該放到新伺服器上

[root@web-8 /opt/nginx-1-19-0/conf/extra]#cat linux0224.conf 
server {
    listen 80;
    server_name linux0224.com ;
    location / {
        root /linux0224.com/;
        index index.html;
    }
}



#新網站的資料檔案
[root@web-8 /opt/nginx-1-19-0/conf/extra]#mkdir /linux0224.com/
[root@web-8 /opt/nginx-1-19-0/conf/extra]#
[root@web-8 /opt/nginx-1-19-0/conf/extra]#
[root@web-8 /opt/nginx-1-19-0/conf/extra]#echo 'new domain  linux0224.com ' > /linux0224.com/index.html

配置客戶端,做好域名解析

windows去測試 hosts檔案

10.0.0.8 laoliulinux.cc linux0224.com


302的實際用法(redirect)

302,域名的臨時跳轉,一般是結合業務的臨時修改
臨時跳轉,一般都是企業內部的活頁域名,不是二級域名的修改。

看懂扣1,不懂2


# 基於訪問路徑的url
# 跳轉到3級域名的活動頁面的操作
# location,和rewrite的玩法,就很清晰了

www.laoliulinux.cc/phone  舊域名
↓
跳轉到3級域名,302也
phone.laoliulinux.cc


# 換這個引數,就是302,臨時跳轉
rewrite /  http://linux0224.com redirect;

舊網站的虛擬主機

server {
    listen 80;
    server_name www.laoliulinux.cc;
    # 新增匹配的活頁url
    # 本次是302引數 redirect
    location /phone {
   		 rewrite / http://phone.laoliulinux.cc redirect;
    }
}

# 讓使用者去訪問 www.laoliulinux.cc/phone
自動跳轉到 
http://phone.laoliulinux.cc這個新域名

新的活頁頁面網站

# 建立配置檔案

server {
    listen 80;
    server_name phone.laoliulinux.cc;
    location / {
        root /phone.laoliulinux.cc/;
        index index.html;
    }
}

# 建立測試資料
[root@web-8 /opt/nginx-1-19-0/conf/extra]#
[root@web-8 /opt/nginx-1-19-0/conf/extra]#mkdir /phone.laoliulinux.cc/
[root@web-8 /opt/nginx-1-19-0/conf/extra]#
[root@web-8 /opt/nginx-1-19-0/conf/extra]#echo 'new website  !!!!!!!!!!!  phone.laoliulinux.cc !!!!!welcome you !!' > /phone.laoliulinux.cc/index.html

測試配置檔案是否正確

[root@web-8 /opt/nginx-1-19-0/conf/extra]#nginx -t
nginx: the configuration file /opt/nginx-1-19-0/conf/nginx.conf syntax is ok
nginx: configuration file /opt/nginx-1-19-0/conf/nginx.conf test is successful
[root@web-8 /opt/nginx-1-19-0/conf/extra]#nginx -s reload

測試客戶端的訪問

做好dns解析
10.0.0.8 laoliulinux.cc linux0224.com phone.laoliulinux.cc www.laoliulinux.cc

rewrite中的break和last引數

在虛擬主機中,可以定義多個location來處理多個url,進行多個動作的設定。

www.yuchaoit.cn/home/xxxxxxxxxxxx
www.yuchaoit.cn/movie/xxxxxxxxxxxxxx

多個location之間,可以基於last,break去設定匹配規則,比較高階了。。
知道語法即可。


實際用法(last)

可以從 location {}  >  location {}  > location {}
多次匹配。

訪問AAA、重寫到BBB、重寫到CCC,且是伺服器內部跳轉。

訪問AAA
伺服器內部跳轉BBB
最後跳轉到CCC

配置檔案

# 建立測試資料,用於檢視url內部跳轉效果,以及保持了url的引數

# 1.建立測試資料
mkdir -p /linux0224/
echo 'i am ccc,  how are you ~~~' > /linux0224/hello.html


# 2.配置檔案
server {
    listen 30000;
    server_name _;

    #
    location /CCC {
        alias /linux0224/;
    }

    location /BBB {
        rewrite ^/BBB/(.*)$ /CCC/$1 last;
    }

    location /AAA {

        rewrite ^/AAA/(.*)$ /BBB/$1 last;
    }

}

圖解跳轉關係 ,第一次跳轉

第二次跳轉,最終的訪問效果

測試last的訪問形式

break引數

break是在本條規則匹配完畢後,終止匹配,不再匹配後面的location{};

表示中斷匹配,訪問到AAA資源後,只rewrite跳轉一次,終止後續的跳轉。

# 建立測試資料,用於檢視url內部跳轉效果,以及保持了url的引數

配置檔案如下

server {
    listen 31000;
    server_name _;

    #
    location /CCC {
        root /www/;
        index index.html;
    }

    location /BBB {
      root /www/;
        index index.html;
        rewrite ^/BBB/(.*)$ /CCC/$1 last;
    }

    location /AAA {
        root /www/;
        index index.html;
        rewrite ^/AAA/(.*)$ /BBB/$1 break;
    }

}

得建立好測試的資料

mkdir -p /www/{AAA,BBB,CCC}
echo 'AAA' > /www/AAA/index.html
echo 'BBB' > /www/BBB/index.html
echo 'CCC' > /www/CCC/index.html


相關文章