快速掌握Nginx(二) —— Nginx的Location和Rewrite


1 location詳解

1.location匹配規則

  Nginx中location的作用是根據Url來決定怎么處理用戶請求(轉發請求給其他服務器處理或者查找本地文件進行處理)。location支持正則表達式,配置十分靈活。我們可以在一個虛擬主機(nginx中的一個server節點)下配置多個location以滿足如動靜分離,防盜鏈等需求。

  location語法是: location [=|~|~*|^~]  /uri/ {… },具體解釋如下表:

符號

含義

location  =    /url

=   :開頭,表示精確匹配,uri必須完全一致才能匹配成功

location  ^~ /Purl

^~:Puri和請求url的開頭相同就匹配成功,且不再去匹配正則,也屬於普通匹配

location        /Purl

普通匹配,Purl和用戶請求url的開頭相同就匹配成功,如果有多個普通匹配都匹配成功則按最長的 。

  如有location /static/,和oaction /static/img/  當請求是www.mysite.com/static/img/1.jpg時,第二個location匹配的更長,所以和第二個loaction匹配成功。

location   ~   reg

~  :區分大小寫的正則匹配

location  ~*  reg

~* :不區分大小寫的正則匹配

location的匹配順序是: = /url   >   ^~ /Purl   > /Purl   >  ~ 和 ~* ,具體流程如下圖所示,需要注意:一般情況下,匹配成功了普通字符串location后還會進行正則表達式location匹配。兩種情況除外:①使用“=”,即精准匹配,如果匹配成功就立即停止其他匹配;②使用“^~”前綴,這個前綴告訴nginx ,如果匹配成功不再進行正則匹配。

簡單總結:

1.  先進行精准匹配,如果匹配成功,立即返回結果並結束匹配過程。

2.  進行普通匹配,如果有多個location匹配成功,將“最長前綴”的location作為臨時結果(如果是 ^~類型的普通匹配成功則直接返回結果,結束匹配過程)。

3.  由上至下逐一進行正則匹配,一旦匹配成功1個,立即返回結果,並結束解析過程;如果沒有一個正則匹配成功,那么將普通匹配的最長前綴location作為最終結果返回,並結束匹配過程。

2. 實際使用建議

實際使用中,個人覺得每個虛擬主機下(server節點下)至少有三個匹配規則定義,如下:
#直接匹配網站根,通過域名訪問網站首頁比較頻繁,使用這個會加速處理,官網如是說。
#這里是直接轉發給后端應用服務器了,也可以是一個靜態首頁
# 第一個必選規則
location = / {
    proxy_pass http://tomcat:8080/index
}
# 第二個必選規則是處理靜態文件請求,這是nginx作為http服務器的強項
# 有兩種配置模式,目錄匹配或后綴匹配,任選其一或搭配使用
location ^~ /static/ {
    root /webroot/static/;
}
location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {
    root /webroot/res/;
}
#第三個規則就是通用規則,用來轉發動態請求到后端應用服務器
#非靜態文件請求就默認是動態請求,自己根據實際把握
#畢竟目前的一些框架的流行,帶.php,.jsp后綴的情況很少了
location / {
    proxy_pass http://tomcat:8080/
}

實際使用建議參考自:https://segmentfault.com/a/1190000002797606

2 rewrite詳解

1 rewrite簡單認識

  rewrite模塊即ngx_http_rewrite_module模塊,主要功能是實現URI重定向。rewrite模塊會通過正則匹配重寫URI,然后內部跳轉再匹配location,或者直接做30x重定向返回客戶端。Nginx的rewrite功能需要PCRE的支持,PCRE是perl兼容正則表達式庫。rewrite指令的語法十分簡單如下:

 rewrite將符合正則的內容替換為新的替代內容
rewrite <regex> <replacement>
[flag]; 關鍵字 正則 替代內容 flag標記 正 則: perl兼容正則表達式語句進行規則匹配 替代內容: 將正則匹配的內容替換成replacement flag標記: rewrite支持的flag標記 ------------------------------------------------------------------------------- flag標記說明: last #匹配完成后不再匹配當前環境下的其他rewrite指令,開始匹配新的location URI規則 break #匹配完成即終止,不再匹配后面的任何規則 redirect #返回302臨時重定向,瀏覽器地址會顯示跳轉后的URL地址 permanent #返回301永久重定向,瀏覽器地址欄會顯示跳轉后的URL地址

使用rewrite時也會用到,幾個常用的指令匯總如下:

指令

使用范圍

作用

if ( condition ){ // 符合條件執行}

location,server

條件判斷。

=     !=  判斷是否相等

~     ~* 判斷是否符合正則

-e    !-e 判斷文件,目錄,符號鏈接是否存在

-d    !-d 判斷目錄是否存在

-f     !-f 判斷文件是否存在

-x    !-x 判斷是否可執行

break

server,location,if

不再繼續執行任何指令,直接退出規則的執行

return 

server,location,if

結束規則的執行和返回狀態碼給客戶端;如 return 403;

set  variable  ‘value’

 http,server,location,if

 新建變量,並賦值 ;如 set varx 'hello'

  

   一個簡單的栗子,簡單了解下rewrite:

server{
        listen 80;
        server_name www.mysite.com;
        #在server中調轉到 愛奇藝
        #rewrite ^/(.*) https://www.iqiyi.com break;
        location = /{
                #location中跳轉到百度
                rewrite ^/(.*) http://www.baidu.com;
                root html;
                index index.html;
        }
        #日志記錄
        error_log logs/mysite.error.log error;
        access_log  logs/mysite.access.log  main;
}       

  我們知道默認情況訪問nginx的虛擬主機會展示nginx的歡迎界面,我們通過rewrite指令跳轉到百度。輸入虛擬機的IP,訪問結果不再是nginx歡迎頁,而是302跳轉到百度如下:

 2 rewrite的執行過程

  nginx中我們可以有多個rewrite指令,默認情況下rewrite從上到下依次執行,並按最后一個匹配成功的作為最終結果。一種特殊情況是當replacement中包含http/https等協議名時,直接302跳轉到replacement指定的url,不再執行后續的rewrite指令。
  那么如果我們想在執行一條rewrite指令后不再執行后續指令怎么辦呢?這時就可以用rewrite中的flag標記,四種flag標記都可以實現不再往下執行其他rewrite指令的作用,但是每種flag標記的使用場景不同。介紹語法的時候已經介紹了四種flag的作用,我們來看一個栗子吧:
server{
        listen 80;
        server_name www.mysite.com;
        location = /{
                #跳轉到百度
                rewrite ^/(.*) http://www.baidu.com;
           #跳轉到/test1
                rewrite ^/(.*) /test1;
           #跳轉到/test2
                rewrite ^/(.*) /test2;
                root html;
                index index.html;
        }
        location /test1{
                return 401;
        }
        location /test2{
                return 402;
        }

        #日志記錄
        error_log logs/mysite.error.log error;
        access_log  logs/mysite.access.log  main;
}

  server進行上邊的配置時,我們訪問虛擬機IP 192.168.70.132,會跳轉到百度頁面,因為replacement包含了http協議名,不在執行后續的rewrite指令;

  如果把第一個rewrite注釋掉,會調整到402錯誤頁,因為rewrite的最終結果時以最后一個匹配成功的為准,最后匹配到 rewite /test2指令,然后找到location /test2返回402錯誤碼;

  如果我們在rewrite  ^?(.*)  /test1后邊加上last標記 ,表示不再匹配后邊的rewrite,會跳到401錯誤頁,url不變還是http://192.168.70.132;

  如果我們在rewrite  ^?(.*)  /test1后邊加上redirect 或者 permanent 標記 ,表示不再匹配后邊的rewrite,會跳轉到401錯誤頁(redirect的跳轉碼為302,permanet的跳轉碼時301),url會改變成 http://192.168.70.132/test1;

  如果我們在rewrite  ^?(.*)  /test1后邊加上break標記 ,表示不再匹配任何規則,會跳轉到404錯誤頁;因為break標記不會再執行任何規則,所以不會再去找location test1,而是直接找 html/test1資源,所以出現404錯誤。

3 一些常用的全局變量

  在使用rewrite指令時我們經常會用到一些常用的全局變量,這些全局變量定義在nginx/conf/fastcgi.conf中,列舉如下:
 

變量

含義

$args

請求中的參數,同$query_string

$content length

請求頭中的Content-length字段。

$content_type

請求頭中的Content-Type字段。

$document_root

當前請求在root指令中指定的值。

$host

請求主機頭字段,否則為服務器名稱。

$http_user_agent

用戶代理,一般為用戶瀏覽器信息

$http_cookie

客戶端cookie信息

$limit_rate

這個變量可以限制連接速率。

$request_method

客戶端請求的動作,通常為GET或POST。

$remote_addr

客戶端的IP地址。

$remote_port

客戶端的端口。

$remote_user

已經經過Auth Basic Module驗證的用戶名。

$request_filename

當前請求的文件路徑,由root或alias指令與URI請求生成。

$scheme

協議名(如http,https)。

$server_protocol

請求使用的協議,通常是HTTP/1.0或HTTP/1.1。

$server_addr

服務器地址,在完成一次系統調用后可以確定這個值。

$server_name

服務器名稱。

$server_port

請求到達服務器的端口號。

$request_uri

包含請求參數的原始URI,不包含主機名,如”/user/getuser?id=100”。

$uri

不帶請求參數的當前URI,$uri不包含主機名,如”/user/getuser”。

$document_uri

與$uri相同。

這里列舉幾個rewrite的簡單栗子來幫助理解:

① 禁止特定IP訪問
server{
        listen 80;
        server_name localhost;
        location /{
        #如果客戶端IP是192.168.70.1,那么拒接響應
           if ($remote_addr = 192.168.70.1){
                 return 403;
           }
           root html;
           index index.html;
        }
}

  通過IP為192.168.70.1的電腦去訪問時,結果如下:

② 根據瀏覽器不同跳轉到不同頁面
     #如果是google訪問的,重定向到 html/chrome.html頁面
        location /{
                if ($http_user_agent ~ Chrome){
                        rewrite ^.*$  /chrome.html;
                        break;
                }
                root html;
                index index.html;
        }

③ 文件不存在返回404,寫的比較繁瑣,主要是演示rewrite的用法

server{
        listen 80;
        server_name www.mysite.com;
        location /{
        #如果文件不存在,跳轉到notfound,
                if (!-f  /usr/local/nginx/html/aaa.html){
                        rewrite ^/(.*) /notfound ;
                }
                root html;
                index index.html;
        }
        location ~ /notfound {
                return 404;
        }
        error_log logs/mysite.error.log error;
        access_log  logs/mysite.access.log  main;
}

小結:loaction和rewrite是nginx中最核心的指令,通過location和rewrite我們可以實現動靜分離/規范客戶端url等功能,因為支持perl的正則表達式,用法十分靈活。這里簡單做了一些總結,如果有不正確的地方請指出。

參考文章:

【1】https://www.cnblogs.com/coder-yoyo/p/6346595.html

【2】https://www.cnblogs.com/czlun/articles/7010604.html

【3】https://www.cnblogs.com/crazylqy/p/6892010.html

 
 
 
        

 


免責聲明!

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



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