Nginx rewrite 詳解

2022-12-08 12:01:22

Nginx rewrite 詳解

本篇主要介紹 nginx 的 rewrite 重定向這個功能進行 詳解介紹, 以及介紹它的使用場景

1. rewrite 基本介紹

rewrite是實現URL重寫的關鍵指令,根據regex (正規表示式)部分內容,重定向到replacement,結尾是flag標記。

基本語法:

rewrite 	<regex> 	<replacement> 	[flag];
關鍵字 		正則 				替代內容 			flag標記
  • regex: 正規表示式語句進行規則匹配
  • replacement: 將正則匹配的內容替換成replacement
  • flag: last | break | redirect | permanent
    • last : 本條規則匹配完成後,繼續向下匹配新的location URI規則
    • break: 本條規則匹配完成即終止,不再匹配後面的任何規則
    • redirect : 回302臨時重定向,瀏覽器地址會顯示跳轉後的URL地址 (防爬蟲)
    • permanent : 返回301永久重定向,瀏覽器位址列會顯示跳轉後的URL地址

rewrite 使用位置

  • server : 在server中針對所有的請求
  • location : 在 location 中則針對 單個匹配路徑的
  • If

2. server 中使用 rewrite

直接在server中使用 rewrite , 它會被先執行 優先於 location 中的

2.1 rewrite 外部站點

rewrite 到外部站點 是指 replacement 部分 是一個完整的 帶 http/https 的 外部路徑 ,它的特點是 瀏覽器會再次請求這個新的站點 所以瀏覽器上的地址一定會發生變化 不受 flag 引數影響

全部攔截 ^/(.*)$

下面的設定是 所有的請求都轉發了 https://www.askajohnny.com

...
server {
        listen       80;
        server_name  www.testfront.com;
        #由於是外部站點帶http/s 的 所以不受flag 影響  break last .. 都會進行跳轉並且變更瀏覽器url
        rewrite ^/(.*)$ https://www.askajohnny.com break;

        location / {
            root html;
            index index.html;
        }
}
...

部分匹配

server {
        listen       80;
        server_name  www.testfront.com;
        #只有當字尾是 數位.html 的時候才會轉發到  https://www.askajohnny.com
        rewrite ^/([0-9]+).html$ https://www.askajohnny.com break;
        #其他的請求會走到這個location中
        location / {
            root html;
            index index.html;
        }
}

經過測試可以發現 直接跳轉過去 並且 瀏覽器中的地址也直接變成了 https://www.askajohnny.com , 待會我們再詳細討論 什麼時候會變化這個地址

比如在我的 部落格網站中 我把http 的請求全部rewrite 轉發到 https 上了, 因為我的QQ登入當時填寫的回撥是 http,又因為QQ互聯的稽核太麻煩 太慢 所以乾脆就這樣設定

2.2 rewrite 到內部站

rewrite 到內部站點是指 replacement 不帶http/https 而是內部的另外一個路徑 , 相當於存取隱藏起來的這個 內部路徑, 只有這種內部站點跳轉的時候 瀏覽器才有可能不變地址 要看 rewite flag 引數了 last 和 break 都不會變的, 只有 redirect 和 permanent

server {
        listen       80;
        server_name  www.testfront.com;
        #只有當字尾是 數位.html 的時候才會轉發到  https://www.askajohnny.com
        rewrite ^/([0-9]+).html$ /my.gif break;
        #其他的請求會走到這個location中
        location / {
            root html;
            index index.html;
        }
        # 上面的rewrite 會被路由到這裡 並且瀏覽器是不會感知到的 
        location /my.gif {
            root /www/static/;
        }
}

經過測試 當存取 www.testfront.com/222.html 的時候

  • flag = last 瀏覽器不會變化 隱藏了 後端 /my.gif 地址
  • flag = break 瀏覽器不會變化 隱藏了 後端 /my.gif 地址
  • flag = redirect 和 permanent 瀏覽器變化了URL 變更狀態碼 302和 301

3. location 中使用rewrite

location 中也可以使用 rewrite 意思是隻有匹配到 這個location 後才經過 rewrite 的正則通過後 再跳轉

和上面一樣 也分為 rewirte 的 replacement 是否包含http和https 外部站點

希望是如果 存取的字尾 是 數位.html 則 返回 my.gif 圖 ,其他的都代理到 http://www.testbackend.com

server {
        listen       80;
        server_name  www.testfront.com;

        #rewrite ^/([0-9]+).html$ /my.gif last;

        location /my.gif {
	   			root /www/static/;
				}

        location / {
            rewrite ^/([0-9]+).html$ /my.gif break;
            proxy_pass http://www.testbackend.com;
        }
 }

經過測試 只有存取www.testfront.com/數位.html 的時候 才能獲取到 my.gif 檔案

4. 使用場景模擬

4.1 基於域名跳轉

比如現在你所在的公司 網站域名是 www.testfront.com 現在需要使用新的域名 www.newtestfront.com 替代, 但是舊的域名不能作廢, 需要讓舊的域名跳轉到新的域名上 , 並且保持後面引數不變

模擬原本設定

server {
        listen       80;
        server_name  www.testfront.com;
        
        location / { 
            proxy_pass http://www.testbackend.com;
        }
 }

新設定,使用rewrite 操作 當存取老的域名 www.testfront.com 跳轉到 新的 www.newtestfront.com

   server {
        listen       80;
        server_name  www.testfront.com ...;

        location / {
            # $host 是可以拿到存取的主機名
            if ( $host = 'www.testfront.com' ) {

                rewrite ^/(.*)$ http://www.newtestfront.com/$1 permanent;
            }

            proxy_pass http://www.testbackend.com;
        }

       location ^~ /static/ {
	    		root  /www/static;
			 }
    }

    server {
        listen       80;
        server_name  www.newtestfront.com;

        location / {
           # 這裡可以改成 新域名的 新後端代理的服務, 依據實際情況
           proxy_pass http://www.testbackend.com;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
   }

4.2 基於使用者端 IP 存取跳轉

今天公司業務新版本上線,要求所有 IP 存取任何內容都顯示一個固定維護頁面,只有公司IP:192.168.200.100存取正常。

   server {
        listen       80;
        server_name  www.testfront.com ...;
        
        # 先設定 rewrite變數為true
        set $rewrite true;
         
        # 當用戶端ip 是172.16.225.1 的時候 才不 rewrite
        if ( $remote_addr = "172.16.225.1" ) {
           set $rewrite = false;
        }
        
        if ( $rewirte = true) {
           # 將rewrite到 維護介面 weihu.html
           rewrite (.+) /weihu.html; 
        }
        
        location /weihu.html {
           # 如果要使用 echo 則需要載入 echo-nginx-module 才行
        	 echo "remote_addr: $remote_addr";
           root /www/weihu/;
        }

        location / {
         		# 如果要使用 echo 則需要載入 echo-nginx-module 才行
        		echo "remote_addr: $remote_addr";
            # 如果是 remote_addr 是特定的ip 則直接正常存取後臺
            proxy_pass http://www.testbackend.com;
        }
    }

此時如果是 172.16.225.1 存取就可以到 後端, 如果是其他的使用者端ip 存取就只能到 weihu.html 頁面

注意 下面是 echo-nginx-module 模組需要單獨下載載入 如果你需要偵錯的話

git clone https://gitee.com/yaowenqiang/echo-nginx-module.git

總結

本篇主要介紹了 nginx 中 rewrite 的基本概念 以及基本的使用方式 ,rewrite 可以出現在 server , location , if 中

並且介紹了 什麼時候才會變化瀏覽器URL , 以及介紹了2個模擬場景

  • rewirte 內部站點

    當rewrite 到內部站點的時候 會根據 flag 引數 last break不變 redirect permanent 變化

  • rewrite 外部站點 帶http/https 等

    當rewrite 外部站點 不管flag 引數 瀏覽器URL都會進行變化 相當於瀏覽器進行了 二次請求了

歡迎大家存取 個人部落格 Johnny小屋
歡迎關注個人公眾號