天天看點

Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發

目錄

  • 前言
  • 一、Nginx中的 正規表達式
  • 二、location 比對
    • 2.1 location常用的比對規則
    • 2.2 location 優先級
    • 2.3 location 示例說明
    • 2.4 必選規則
  • 三、rewrite 轉發
    • 3.1 Rewrite 介紹
    • 3.2 Rewrite 實作
    • 3.3 rewrite 執行順序
    • 3.4 rewrite 文法格式
    • 3.5 flag 标記說明
    • 3.6 rewrite 示例
      • 3.6.1 基于域名的跳轉
      • 3.6.2 基于用戶端 IP 通路跳轉
      • 3.6.3 基于舊域名跳轉到新域名後面加目錄
      • 3.6.4 基于參數比對的跳轉
      • 3.6.5 基于目錄下所有 php 結尾的檔案跳轉
      • 3.6.6 基礎url 跳轉
      • 總結:
    • 練習題
        • 1、
        • 2、
        • 3、
        • 4、
        • 5、

前言

一、Nginx中的 正規表達式

^ :比對輸入字元串的起始位置
$ :比對輸入字元串的結束位置
* :比對前面的字元零次或多次。如“ol*”能比對“o”及“ol”、“oll”
+ :比對前面的字元一次或多次。如“ol+”能比對“ol”及“oll”、“olll”,但不能比對“o”
? :比對前面的字元零次或一次,例如“do(es)?”能比對“do”或者“does”,”?”等效于”{0,1}”
. :比對除“\n”之外的任何單個字元,若要比對包括“\n”在内的任意字元,請使用諸如“[.\n]”之類的模式
\ :将後面接着的字元标記為一個特殊字元或一個原義字元或一個向後引用。如“\n”比對一個換行符,而“\$”則比對“$”
\d :比對純數字
{n} :重複 n 次
{n,} :重複 n 次或更多次
{n,m} :重複 n 到 m 次
[] :定義比對的字元範圍
[c] :比對單個字元 c
[a-z] :比對 a-z 小寫字母的任意一個
[a-zA-Z0-9] :比對所有大小寫字母或數字
() :表達式的開始和結束位置
| :或運算符
           

二、location 比對

從功能看 rewrite 和 location 似乎有點像,都能實作跳轉,主要差別在于:

  • rewrite 是在 同一域名内 更改擷取資源的路徑;
  • 而 location 是對一類路徑做 控制通路 或 反向代理,還可以通過 proxy_pass 到其他機器。

2.1 location常用的比對規則

比對分類:

精準比對:location = / {}             #精準、完全比對
正則比對:location ~ / {}             #和 正規表達式搭配使用
一般比對:location / {}               #從根目錄開始的路徑
           

比對規則:

=   : 進行普通字元精确比對,也就是完全比對。
^~  : 表示普通字元比對。使用字首比對。【如果比對成功,則不再比對其它 location。】
~   : 區分大小寫的正則比對。
~*  : 不區分大小寫的正則比對。
!~  : 區分大小寫的正則比對取反。    
!~* : 不區分大小寫的正則比對取反。
           

2.2 location 優先級

首先精确比對 =
其次是 正則字首比對 ^~
其次是按檔案中順序的正則比對 ~ 或 ~*
然後比對不帶任何修飾的普通字首比對,如 /bbs
最後是交給 / 根比對
           

比對類型:

普通類型

正則類型

2.3 location 示例說明

(1)location = / {}
=為精确比對 / ,主機名後面不能帶任何字元串,優先級最高
比如通路 / 和 /data,則 / 比對,/data 不比對
再比如 location = /abc,則隻比對/abc ,/abc/或 /abcd不比對。若 location  /abc,則即比對/abc 、/abcd/ 同時也比對 /abc/。

(2)location / {}
因為所有的位址都以 / 開頭,是以這條規則将比對到所有請求 比如通路 / 和 /data, 則 / 比對, /data 也比對,
但若後面是正規表達式會和最長字元串優先比對(最長比對),比如 /a/b/c/d, 比對 /a/b/c 優先大于 /a/b 優先大于 /a

(3)location /documents/ {}
比對任何以 /documents/ 開頭的位址,比對符合以後,還要繼續往下搜尋其它 location
隻有其它 location後面的正規表達式沒有比對到時,才會采用這一條

(4)location /documents/abc {}
比對任何以 /documents/abc 開頭的位址,比對符合以後,還要繼續往下搜尋其它 location
隻有其它 location後面的正規表達式沒有比對到時,才會采用這一條

(5)location ^~ /images/ {}
比對任何以 /images/ 開頭的位址,【比對符合以後,停止往下搜尋正則,采用這一條】

(6)location ~* \.(gif|jpg|jpeg)$ {}
不區分大小寫比對所有以 gif、jpg或jpeg 結尾的請求
然而,所有請求 /images/ 下的圖檔會被 location ^~ /images/ 處理,因為 ^~ 的優先級更高,是以到達不了這一條正則

(7)location /images/abc {}
最長字元比對到 /images/abc,優先級最低,繼續往下搜尋其它 location,會發現 ^~ 和 ~ 存在

(8)location ~ /images/abc {}
比對以/images/abc 開頭的,優先級次之,隻有去掉 location ^~ /images/ 才會采用這一條

(9)location /images/abc/1.html {}
比對/images/abc/1.html 檔案,如果和正則 ~ /images/abc/1.html 相比,正則優先級更高

           

優先級總結:

2.4 必選規則

實際網站使用中,至少有三個比對規則定義:

第一個必選規則:

  • 直接比對網站根,通過域名通路網站首頁比較頻繁,使用這個會加速處理,比如說官網。
  • 也可以是一個靜态首頁,可以直接轉發給後端應用伺服器
location = / {
	root html;
    index index.html index.htm;
}
           

第二個必選規則:

  • 第二個必選規則是 處理靜态檔案請求,這是 nginx 作為 http 伺服器的強項;
  • 有兩種配置模式,目錄比對 或 字尾比對,可任選其一或搭配使用
location ^~ /static/ {               #目錄比對
    root /webroot/static/;         
} 

#字尾比對,如果是這些檔案名字尾的,就通路 /webroot/res/ 目錄
location ~* \.(html|gif|jpg|jpeg|png|css|js|ico)$ {       
    root /webroot/res/;
}
           

比如 www.daun.com/static/1.jpg、www.daun.com/static/abc/1.jpg 都被上面的目錄比對比對了。

第三個必選規則:

  • 通用規則,比如用來轉發以

    .php、.jsp

    字尾的動态請求到後端應用伺服器;
  • 非靜态檔案請求就預設是動态請求
location / {
    proxy_pass http://tomcat_server;
}
           

一個網站的比對規則設定:

一般先給首頁做個靜态比對(備胎比對),再給靜态頁面寫幾個可能性的靜态比對,剩下的就是動态的通用比對規則了。

三、rewrite 轉發

3.1 Rewrite 介紹

rewrite 功能:使用 nginx 提供的 全局變量 或 自己設定的變量,結合正規表達式 和 标記 實作 URL重寫以及重定向。

例如:

  • 更換域名後 需要保持 舊的域名能夠轉到新的域名上;
  • 某網頁發生改變 需要跳轉到新的頁面;
  • 網站防盜鍊;
  • 等等

Rewrite 跳轉場景:

  • 為了讓搜尋引擎搜錄網站内容及使用者體驗更好,企業會将 動态URL位址 僞裝成 靜态位址提供服務;
  • 網址換新域名後,讓舊的通路跳轉到新的域名上。

    比如通路 www.360buy.com 就能重定向到 www.jd.com/

  • 服務端某些業務調整,比如根據特殊變量、目錄、用戶端的資訊進行URL調整等。

注意:rewrite 隻能放在配置檔案中的 server{},location{},if{} 子產品中,并且預設隻能對域名後面的除去傳遞的參數外的字元串起作用。

例如:http://www.lisi.com/a/we/index.php?id=1&u=str
隻會對 /a/we/index.php 重寫。
           

3.2 Rewrite 實作

Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發
  • Nginx:通過

    ngx_http_rewrite_module

    子產品支援URL重寫、支援if條件判斷,但不支援else;
  • 跳轉:從一個location跳轉到另一個location,循環最多可以執行10次,超過後nginx将傳回500錯誤;
  • PCRE支援:perl 相容正規表達式的文法規則比對;
  • 重寫子產品set指令:可以建立新的變量并為其指派;

3.3 rewrite 執行順序

優先:執行 server{} 塊裡面的 rewrite 指令
其次:執行 location 比對
最後:執行標明的 location{} 中的 rewrite 指令
           

3.4 rewrite 文法格式

文法: rewrite <regex> <replacement> <flag>;

regex: 表示正則比對規則
replacement: 表示跳轉後的内容
flag: 表示 rewrite 支援的 flag 标記
           

3.5 flag 标記說明

last :本條規則比對完成後,繼續向下比對新的location URI規則,一般用在 server 和 if 中。
break :本條規則比對完成即終止,不再比對後面的任何規則,一般使用在 location 中。
redirect :傳回302臨時重定向, 浏覽器位址會顯示跳轉後的URL位址。
permanent :傳回301永久重定向,浏覽器位址欄會顯示跳轉後的URL位址。
[ˈpɜːmə nənt]
           

3.6 rewrite 示例

3.6.1 基于域名的跳轉

現在公司舊域名 www.test.com 有業務需求變更,需要使用新域名www.lisi.com 代替,但是舊域名不能廢除,需要跳轉到新域名上,而且後面的參數保持不變。

思考:肯定要先有監聽 www.test.com 域名的這個站點 server

vim /usr/local/nginx/conf/nginx.conf

server {
	listen       80;
	server_name  www.test.com;     #域名修改
	charset utf-8;
	access_log  /var/log/nginx/www.test.com.access.log;     #日志修改
	location / {
	    #添加域名重定向
	    # $host 為 rewrite全局變量,代表請求主機頭字段或主機名
	    #^/(.*)$  以根目錄為開頭 結尾不管有沒有目錄和參數
	    #$1為正規表達式比對的内容,即"域名/"之後的字元串,就是rewrite的正則
	    #因為rewrite隻能對域名後面的除去傳遞的參數外的字元串起作用,是以http://www.域名.com/ 要輸寫
	    
	    if ($host = 'www.test.com'){
	        rewrite ^/(.*)$ http://www.lisi.com/$1 permanent;
	    }
        root   html;         #通路頁面還是主站點下的首頁
        index  index.html index.htm;
    }
}

#添加域名解析
echo "192.168.31.101 www.lisi.com www.test.com" >> /etc/hosts

systemctl restart nginx

浏覽器輸入模拟通路 http://www.test.com/1.html(内容不存在的)
會跳轉到www.lisi.com/1.html,檢視元素可以看到傳回301,實作了永久重定向跳轉,而且域名後的參數也正常跳轉。
           
Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發
Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發
Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發

添加域名解析

Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發

nginx -t , 重新開機 nginx 服務,清楚浏覽器緩存。

浏覽器通路 www.test.com 。會發現被 rewrite 重定向到了 www.lisi.com , 标記說明用的 permanent ,是以會傳回 301,如果改成 redirect ,傳回就是302.

Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發
Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發

因為rewrite 隻對域名後面的除去傳遞的參數外的字元串起作用,因為後面的

/test/.html

會被直接 作為 $1 拼接到 www.lisi.com/ 後面 。

3.6.2 基于用戶端 IP 通路跳轉

需求:今天公司業務新版本上線(或停機維護),要求 所有 IP 通路任何内容都顯示一個固定維護頁面,隻有公司 IP:192.168.31.101 通路正常。

通過 set 指令 來設定自己的變量,來進行判斷。

vim /usr/local/nginx/conf/nginx.conf
server {
	listen       80;
	server_name  www.test.com;
	charset utf-8;
	access_log  /var/log/nginx/www.test.com.access.log;

	#設定是否合法的IP标記;設定變量$rewrite,變量值為boole值true
    set $rewrite true;
    #判斷是否為合法IP;當用戶端IP為 192.168.31.101 時,将變量值設為false,不進行重寫
    if ($remote_addr = "192.168.31.101"){
        set $rewrite false;
    }
    
	#除了合法IP,其它都是非法IP,進行重寫跳轉維護頁面
	#當變量值為true時,進行重寫
    if ($rewrite = true){
        #重寫在通路IP後邊插入/weihu.html,例如192.168.31.111/weihu.html
        #(.+) 表示正則能夠比對所有路徑
        rewrite (.+) /weihu.html;
    }
    
    #維護之後,需要加一個location 進行精确比對到weihu.html
    #不寫這個location 的話就轉到下面的location中去了
    location = /weihu.html {
        #網頁傳回/var/www/html/weihu.html的内容
        root /var/www/html;
    }
    
	location / {
        root   html;
        index  index.html index.htm;
    }
}
           
mkdir -p /var/www/html/
echo "<h1>As server maintenance, please visit later, thank you.</h1>" > /var/www/html/weihu.html
echo "192.168.163.10 www.test.com" >> /etc/hosts

nginx -t
systemctl restart nginx
           
Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發
Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發
Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發

浏覽器通路

隻有 IP 為 192.168.31.101 能正常通路,其它位址都會重定向到 維護頁面。

Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發

這時候比如打開一台同一網段的Windows 主機,添加 192.168.31.101 www.test.com 到 C:\Windows\System32\drivers\etc\hosts 中。

通路 www.test.com

Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發

成功轉到 weihu.html 頁面。

通路 http://www.test.com/test/1.html 結果也一樣。

注意:

如果rewrite (.+) /weihu.html;
改成rewrite (.+) /weihu.html permanent;  的話,
如果是非 192.168.31.101 的主機通路 會使浏覽器修改請求通路的URL成 http://www.test.com/weihu.html 再請求通路,
這樣就會進入一直在 rewrite的死循環,通路請求會一直被重寫成 http:/ /www.kgc.com/weihu.html  再請求通路.....

是以頁面跳轉 不因該加上 permanent
           

3.6.3 基于舊域名跳轉到新域名後面加目錄

比如,現在通路的是

http://bbs.test.com/post/

,現在需要将這個域名下面的通路都跳轉到

http://www.test.com/bbs/post/

vim /usr/local/nginx/conf/nginx.conf

server {
	listen       80;
	server_name  bbs.test.com;
	charset utf-8;
	access_log  /var/log/nginx/bbs.test.com.access.log;
	
	#添加;這裡的$1為位置變量,代表的就是: /post
	#比對通路路徑,根目錄出發的目錄
	location /post {
        rewrite (.+) http://www.test.com/bbs$1 permanent;
    }
    
	location / {
        root   html;
        index  index.html index.htm;
    }
}
           
mkdir -p /usr/local/nginx/html/bbs/post
echo "this is 1.html" > /usr/local/nginx/html/bbs/post/1.html
echo "192.168.31.101 bbs.test.com www.test.com" >> /etc/hosts

systemctl restart nginx.service
使用浏覽器通路
http://bbs.test.com/post/1.html 
就會跳轉到
http://www.test.com/bbs/post/1.html
           
Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發
Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發

nginx -t

systemctl restart nginx.service

通路

http://bbs.test.com/post/1.html

就會跳轉到

http://www.test.com/bbs/post/1.html

Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發

3.6.4 基于參數比對的跳轉

現在通路

http://www.test.com/100-(100|200)-100(任意數字).html

跳轉到

http://www.test.com

頁面。

vim /usr/local/nginx/conf/nginx.conf

server {
	listen       80;
	server_name  www.test.com;
	charset utf-8;
	access_log  /var/log/nginx/www.test.com.access.log;

    if ($request_uri ~ ^/100-(100|200)-(\d+).html$) {
        rewrite (.+) http://www.test.com permanent;
    }

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

echo "192.168.31.101 www.test.com" >> /etc/hosts
systemctl restart nginx

浏覽器通路
http://www.test.com/100-200-100.html 或 
http://www.test.com/100-100-100.html 
會跳轉到
http://www.test.com 頁面。
           
Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發
Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發
~ ^/100-(100|200)-(\d+).html$  這一塊是正規表達式
以根目錄為開頭 100或200  (\d+) 至少有一個純數字  
           
$request_uri:是個全局變量,包含請求參數的原始URI,但不包含主機名,

如: http;://www.test.com/abc/bbs/index.htmlRa=1&b=2 
$request_uri 就是其中的 /abc/bbs/index.php?a=1&b=2

$uri:這個變量指目前的請求URI,不包括任何參數,
$uri 就是其中的  /abc/bbs/index.html

$document_uri:與$uri相同,這個變量指目前的請求URI,不包括任何傳遞參數,
$document_uri 就是其中的  /abc/bbs/index.html
           

方法二:

不用 if 語句寫,隻用 location 來寫

Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發
#隻用location 來從根目錄出發比對正規表達式也可以。
# 蠻子比對條件後,都能夠執行 rewrite (.+) ...語句操作

location ~ /100-(100|200)-(\d+).html$ {
     rewrite (.+) http://www.test.com permanent;
}
           

3.6.5 基于目錄下所有 php 結尾的檔案跳轉

要求通路

http://www.test.com/upload/abc.php

時跳轉到首頁。

vim /usr/local/nginx/conf/nginx.conf

server {
	listen       80;
	server_name  www.test.com;
	charset utf-8;
	access_log  /var/log/nginx/www.test.com.access.log;
	
location ~* /upload/.*\.php$ {
    rewrite (.+) http://www.test.com permanent;
}

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

echo "192.168.31.101 www.test.com" >> /etc/hosts
systemctl restart nginx

浏覽器通路
http://www.test.com/upload/abc.php 跳轉到http://www.test.com頁面。
           

比對順序

Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發

3.6.6 基礎url 跳轉

要求通路一個具體的頁面如

http://www.test.com/abc/123.html

,跳轉到首頁

Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發

總結:

從功能看 rewrite 和 location 似乎有點像,都能實作跳轉,主要差別在于

  • rewrite 是在同一域
  • location 是對一類路徑做控制通路或反向代理,還可以 proxy_pass 到其他機器

其實就是通過 if 語句 或者 location 中的正規表達式比對,

比對到之後,執行子產品中的 rewrite …語句。

再執行最終滿足比對/優先級條件的 location 子產品體内的 定義的目錄下的首頁。

Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發

練習題

習題:

1、

浏覽器通路 http://www.kgc.com/bbs/index.php 跳轉到http://www.kgc.com頁面。

if ($uri ~ ^/bbs/index.php){
                rewrite (.+) http://www.test.com permanent;
        }
#或
#       location ~* ^/bbs/index.php {
#               rewrite (.+) http://www.test.com permanent;
#       }

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

           

2、

浏覽器通路 http://www.kgc.com/bbs/index.php 或者http://www.kgc.com/post/index.php 跳轉到http://www.kgc.com/test.html頁面。

cd /usr/local/nginx/html/
echo "this is html/test.html" > test.html


vim nginx.conf 

location ~* ^/bbs/index\.php$ {
    rewrite (.+) http://www.test.com/test.html;
  }

           
Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發
Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發

3、

浏覽器通路 http://mail.kgc.com/post/1.html 跳轉到http://www.kgc.com/mail/post/1.html頁面。

[[email protected] html]# mkdir -p mail/post
[[email protected] html]# cd mail/post/
[[email protected] post]# echo "this is mail/post" > 1.html
[[email protected] post]# 
[[email protected] post]# echo "192.168.31.101 mail.test.com" >> /etc/hosts
[[email protected] post]# cat /etc/hosts

vim /usr/local/nginx/conf/nginx.conf

server {
        listen       80;
        server_name  mail.test.com;

        charset utf-8;
        access_log  logs/test.com.access.log;


        location /post {
                rewrite (.+) http://www.test.com/mail$1 permanent;
        }

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


#$1為位置變量

http://mail.test.com/post/1.html 
就會跳轉到
http://www.test.com/mail/post/1.html
           
Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發

4、

浏覽器通路 http://www.accp.com 跳轉到 http://www.kgc.com 頁面,并且保證域名後面的路徑參數不變

server_name  www.test.com;
...

#$host為rewrite全局變量,代表請求主機頭字段或主機名
#$1為正則 ^/(.*) 所比對的内容,就是域名/ 後邊的字元串

  location / {
      if ($host = "www.test.com"){
          rewrite ^/(.*)$ http://www.benet.com/$1 permanent;
      }
      root   html;
      index  index.html index.htm;
  }
           
Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發
通路
http://www.test.com/test.html
重定向為
http://www.benet.com/test.html
           
Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發

5、

隻允許你本機浏覽器能通路 http://www.kgc.com 下的所有頁面,其它主機通路隻能看到維護頁面.

set $rewrite true;
        if ($remote_addr = "192.168.31.101"){
                set $rewrite false;
        }

        if ($rewrite = true){
                rewrite (.+) /weihu.html;
        }

        location = /weihu.html {
                root /var/www/html;
        }
        location / {
            root   html;
            index  index.html index.htm;
        }
           
Nginx 的 location 比對 與 rewrite 重寫跳轉前言一、Nginx中的 正規表達式二、location 比對三、rewrite 轉發

繼續閱讀