Nginx Rewrite相關功能

Nginx服務器利用ngx_http_rewrite_module模塊解析和處理rewrite請求。rewrite用於實現URL的重寫,類似於重定向功能,可以將用戶的請求重寫至別的目錄,另外還可以在一定程度上提高網站的安全性。

- 5.1:ngx_http_rewrite_module模塊命令

https://nginx.org/en/docs/http/ngx_http_rewrite_module.html

- 5.1.1:if指令

用於條件匹配判斷,根據條件判斷結果選擇不同的nginx配置,在server或location中配置。nginx的if語法只能支持單次判斷,不支持多重判斷,用法如下

if (條件匹配) {
    action
}

#示例1
location /main {
    index index.html;
    default_type text/html;
    if ( $scheme = http ){
        echo "if ---> $scheme";
    }
    if  ($scheme = https ){
        echo "if ---> $scheme";
    }
}

使用正則表達式對變量進行匹配,成功爲true,否則false,變量與表達式之間可以用符號鏈接:

=  #比較變量與字符串是否相等
~  #表示在匹配過程中區分大小寫字符
~* #表示在匹配過程中不區分大小寫
-f 和 !-f #判斷請求的文件存在與不存在
-d 和 !-d #判斷請求的目錄存在與不存在
-x 和 !-x #判斷文件是否可執行
-e 和 !-e #判斷請求的文件或目錄是否存在(包括文件,目錄,軟鏈接)

注:若$變量的值爲空或以0開頭,則if指令認爲此條件爲false,其它條件爲true

- 5.1.2 :set指令

指定key並給其定義一個變量,定義格式爲set $key value,只有將內置變量賦值給自定義變量時無論是key還是value都要加$符號

location /main {
    root /data/html;
    index index.html;
    default_type text/html;
    set $name javis;
    echo $name;
    set $my_port &server_port;
    echo $my_port;
}

- 5.1.3:break指令

用於中斷當前相同作用域(location)中的其他配置,停止向下尋找,回到上一層作用域繼續向下讀取配置,該指令可在server塊和location塊以及ig塊中使用,語法如下:

location /main {
    root /data/html;
    index index.html;
    default_type text/html;
    set $name javis;
    echo $name;
    break;
    set $my_port &server_port;
    echo $my_port;
}
#只輸出$name的值javis,不再向下執行

- 5.1.4:return指令

return用於完成隊請求的處理,並直接向客戶端返回響應狀態碼處於此指令後的所有配置都將不被執行,return可以在server、if和location塊進行配置,語法如下

return code #返回給客戶端指定的http狀態碼
return code (text) #返回給客戶端指定的狀態碼及響應內容,可以調用變量
return code URL #返回給客戶端的URL地址
示例1
location /main {
    root /data/html;
    index index.html;
    default_type text/html;
    if ( $scheme = http ){
        return 500 "server error";
        echo "if --->" $scheme; #只輸出server error,後面的將不執行
    }
    if ( $scheme = https){
        echo "if --->" $scheme;
    }
}

- 5.1.5:rewrite_log 指令

設置是否開啓記錄ngx_http_rewrite_module模塊日誌記錄到error_log日誌文件中,可以配置在http、server、location或if當中,需要日誌級別爲notice

location /main {
    root /data/html;
    index index.html;
    default_type text/html;
    set $name javis;
    echo $name;
    rewrite_log on;
    break;
    set $my_port &server_port;
    echo $my_port;
}
#重啓nginx,訪問error_log

- 5.2:rewrite指令

通過正則表達式的匹配倆改變URI,可以同時存在一個或多個指令,按照次序對URI進行匹配,rewrite主要是針對用戶請求的URL或URI作具體處理

URI:通用資源標識符,標識一個資源的路徑,可以不帶協議
URL:統一資源定位符,用於在internet中描述資源的字符串,時URI的子集,主要包括傳輸協議(scheme)、主機(IP、端口號或者域名)和資源具體地址(目錄和文件名)等三部分,一般格式爲 scheme://主機名[:端口號][/資源路徑],如:http://www.a.com:8080/path/file/index.html就是一個URL路徑,URL必須帶訪問協議。
區別:每一個URL都是URI,但URI不都是URL
示例:
http://example.org/path/to/resource.txt #URI/URL
ftp://example.org/resource.txt  #URI/URL
/absolute/path/to/resource.txt  #URI

rewrite官方介紹:https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite,可以配置在server、location、if中,語法如下

rewrite regex replacement [flag];

rewrite將用戶請求的URI基於regex所描述的模式進行檢查,匹配到時將其替換爲表達式指定的新的URI。若在同一級配置模塊中存在多個rewrite規則,就會自上而下逐個檢查;被某規格替換後,會重新一輪新的替換檢查,隱含有循環機制,但不超過10次;若超過則提示500響應嗎,[flag]所標識的標誌位用於控制此循環機制,,如果替換後的URL是以http://或https://開頭,則替換結果會以重定向返回客戶端,即永久重定向301

- 5.2.1:rewrite flag使用介紹

利用nginx的rewrite的指令,可以實現url的重新跳轉,rewrtie有四種不同的flag,分別是redirect(臨時重定向)、permanent(永久重定向)、break和last。其中前兩種是跳轉型的flag,後兩種是代理型,跳轉型是指有客戶端瀏覽器重新對新地址進行請求,代理型是在WEB服務器內部實現跳轉的。

redirect #臨時重定向,重寫完成後以臨時重定向方式直接返回重寫後生成的新URL給客戶端,有客戶端重新發起請求,使用相對路徑,http://或https://開頭,狀態碼:302
permanent #永久重定向,以永久重定向的方式直接返回重寫後生成的新URL給客戶端,由客戶端重新發起新的請求,狀態碼:301
last #重寫完成後停止對當前location中後續的其他重寫操作,而後對新的URL啓動新一輪重寫檢查,不建議在location中使用
break #重寫完成後停止對當前URL在當前location中後續的其他重寫操作,而後直接跳轉至重寫規則匹配塊之後的其他配置;結束循環,建議在location中使用

這裏應該瞭解nginx處理的十一個階段

 NGX_HTTP_POST_READ_PHASE = 0,   #讀取請求頭
 NGX_HTTP_SERVER_REWRITE_PHASE,   #執行rewrite
 NGX_HTTP_FIND_CONFIG_PHASE,  #根據uri替換location
 NGX_HTTP_REWRITE_PHASE,      #根據替換結果繼續執行rewrite
 NGX_HTTP_POST_REWRITE_PHASE, #執行rewrite後處理
 NGX_HTTP_PREACCESS_PHASE,    #認證預處理   請求限制,連接限制
 NGX_HTTP_ACCESS_PHASE,       #認證處理
 NGX_HTTP_POST_ACCESS_PHASE,  #認證後處理, 認證不通過, 丟包
 NGX_HTTP_TRY_FILES_PHASE,    #嘗試try標籤
 NGX_HTTP_CONTENT_PHASE,      #內容處理
 NGX_HTTP_LOG_PHASE           #日誌處理

- 5.2.2:rewrite案例-域名永久與臨時重定向

要求:因業務需要,將訪問原域名www.linux.net的請求永久重定向到www.linux.com

臨時重定向不會緩存域名解析記錄(A記錄),但是永久重定向會緩存

location / {
    root /data/html;
    index index.html;
    rewrite / http://www.linux.com permanent;
    #rewrite / http://www.linux.com redirect;
}

(1)臨時重定向:告訴瀏覽器域名不是固定重定向到當前目標域名,後期可能隨時會更改,因此瀏覽器不會緩存當前域名的解析記錄

(2)永久重定向:永久重定向會緩存DNS解析記錄

- 5.2.3:rewrite案例-URI重定向

要求:訪問break的請求被轉發至image,而訪問last傳遞請求也被轉發至image,以此測試last和break的區別

        location /break {
#       root /data/html;
        rewrite ^/break/(.*) /test/$1 break;#重寫後直接直接找test目錄,若沒有爲此處的test指定根目錄,則訪問不到,換言之,若要成功跳轉,test需要完整路徑
        return 666 "break";
        }
        location /last {
        rewrite ^/last/(.*) /test/$1 last;#完成重寫後,在所有location裏面重新開始一輪遍歷,進到test,訪問成功
        return 888 "last";
        }
        location /test {
        return 999 "test";
        }

重啓nginx的訪問測試

[root@centos ~]$curl -L -i  www.alijiujiu.com/break/ #break不會跳轉至location /test中
HTTP/1.1 404 Not Found
Server: nginx/1.14.2
Date: Sat, 01 Jun 2019 06:14:27 GMT
Content-Type: text/html
Content-Length: 19
Connection: keep-alive
Keep-Alive: timeout=10
ETag: "5cee850d-13"

this is error page

[root@centos ~]$curl -L -i  www.alijiujiu.com/last/ #last會跳轉至location /test中繼續執行匹配操作
HTTP/1.1 999 
Server: nginx/1.14.2
Date: Sat, 01 Jun 2019 06:14:46 GMT
Content-Type: application/octet-stream
Content-Length: 4
Connection: keep-alive
Keep-Alive: timeout=10

test

- 5.2.4:rewrite案例-自動跳轉https

要求:基於通信安全考慮公司網站要求全站https,所以要求將在不影響用戶請求的情況下將http請求全部自動跳轉至https,另外也可以實現部分location跳轉

location / {
    root /data/html;
    index index.html;
    if ( $scheme = http ){ #未加條件判斷,會陷入死循環
        rewrite / https://www.alijiujiu.com permanent;
    }
}

- 5.2.5:rewrite案例-判斷文件是否存在

要求:當用戶訪問公司輸入錯誤的URL,可以將用戶重定向到公司首頁

location / {
    root /data/html;
    index index.html;
    if ( !-f $request_filename ){
        #return 404 "input error";
        rewrite (.*) http://www.alijiujiu.com/index.html;
    }
}

- 5.3:Nginx防盜鏈

防盜鏈基於客戶端攜帶的referer實現,referer是記錄打開一個頁面之前記錄是從哪個頁面跳轉過來的標記信息,如果別人只鏈接了自己網站圖片或某個單獨的資源,而不是打開了網站的整個頁面,這就是盜鏈,referer就是之前的那個網站域名,正常的referer信息有以下幾種

none:請求報文首部沒有referer首部,比如用戶直接在瀏覽器輸入域名訪問web網站,就沒有referer信息。
blocked:請求報文有referer首部,但無有效值,比如爲空。
server_names:referer首部中包含本主機名及即nginx 監聽的server_name。
arbitrary_string:自定義指定字符串,但可使用*作通配符。
regular expression:被指定的正則表達式模式匹配到的字符串,要使用~開頭,例如:~.*\.magedu\.com。

5.3.1:實現防盜鏈

基於訪問安全考慮,nginx支持通過ungx_http_referer_module模塊 https://nginx.org/en/docs/http/ngx_http_referer_module.html#valid_referers 檢查訪問請求的referer信息是否有效實現防盜鏈功能,定義方式如下:

[root@centos ~]$vim /apps/nginx/conf/conf.d/pc.conf
location /image {
    root /data/html/;
    index index.html;
    valid_referers none blocked server_names *.example.com example.* www.example.org/galleries/
    ~\.google\.;
    if ( $invalid_referer ){
        return 403;
    }
}

實現防盜鏈:

location ^~ /images {
 root /data/nginx;
 index index.html;
     valid_referers none blocked server_names *.alijiujiu.com www.alijiujiu.* 
    api.online.test/v1/hostlist  ~\.google\. ~\.baidu\.; #定義有效的referer
 if ($invalid_referer) { #假如是使用其他的無效的referer訪問:
  return 403; #返回狀態碼403
 }
}
#重啓Nginx並訪問測試
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章