這是 Nginx 學習總結的第四篇,上一篇介紹到了 Nginx 學習總結(3) —— Location 模組,這一篇會對Rewrite模組
做一些總結。根據官方文件說明,Rewrite
模組是用於使用 PCRE 正規表示式
更改請求 URI,有條件地選擇配置,並返回重定向。
表面看,
rewrite
和location
的功能有點像,都能實現跳轉,然而它們的區別在於:rewrite
是在同一域名內更改獲取資源的路徑,而location
是對一類路徑做控制訪問或反向代理,並且可以proxy_pass
到其他機器。
很多情況下 rewrite
也會寫在 location
裡,它們的執行順序是:
- 執行
server
塊的rewrite
指令; - 執行
location
匹配; - 執行選定的
location
中的rewrite
指令。
如果其中某步 URI 被重寫,則重新迴圈執行1-3,直到找到真實存在的檔案;迴圈超過10次,則返回
500 Internal Server Error
錯誤。
指令
1. break
停止執行 ngx_http_rewrite_module
模組的指令集,但是其他模組指令不受影響。
Context: server, location, if
server {
listen 80;
# 此處 break 會停止執行 server 塊的 return 指令(return 指令屬於rewrite模組)
# 如果把它註釋掉 則所有請求進來都返回 ok 字串
break;
return 200 "ok";
location = / {
root /usr/share/nginx/html;
index index.php index.html index.htm;
}
}
2. if
依據指定的條件決定是否執行 if 塊語句中的內容。
Context: server, location
if
中的幾種判斷條件:
- 一個變數名,如果變數
$variable
的值為空字串或者字串"0"
,則為false
; - 變數與一個字串的比較,相等為
=
不相等為!=
; - 變數與一個正規表示式的模式匹配,操作符可以是:
~
區分大小寫的正則匹配;~*
不區分大小寫的正則匹配,!~
、!~*
前面兩者的非; - 檢測檔案是否存在,使用
-f
(存在) 和!-f
(不存在); - 檢測路徑是否存在,使用
-d
(存在) 和!-d
(不存在) 後面判斷可以是字串也可是變數; - 檢測檔案、路徑、或者連結檔案是否存在,使用
-e
(存在) 和!-e
(不存在) ,後面判斷可以是字串也可是變數; - 檢測檔案是否為可執行檔案,使用
-x
(可執行) 和!-x
(不可執行),後面判斷可以是字串也可是變數。
可以用作 if
判斷的全域性變數:
-
$args
這個變數等於請求行中的引數,同$query_string
-
$content_length
請求頭中的Content-length
欄位 -
$content_type
請求頭中的Content-Type
欄位 -
$document_root
當前請求在root
指令中指定的值 -
$host
請求主機頭欄位,否則為伺服器名稱 -
$http_user_agent
客戶端agent
資訊 -
$http_cooki
客戶端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,不包含主機名,如/foo/bar.php?arg=baz
-
$uri
不帶請求引數的當前 URI,$uri 不包含主機名,如/foo/bar.html
-
$document_uri
與 $uri 相同
set $variable "0";
if ($variable) {
# 不會執行,因為 "0" 為 false
break;
}
# 變數與一個字串的比較
if ($request_method = POST) {
return 405;
}
# 變數與正規表示式的匹配
if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
set $id $1;
}
if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /msie/$1 break;
}
# 檢查檔案是否存在,字串與變數均可
if ( !-f "/data.log" ) {
break;
}
if ( !-f $filename ) {
break;
}
if
關鍵字後必須加一個空格符
3. return
停止處理並將指定的 code
碼返回給客戶端。 從 0.8.42 版本開始, return
語句可以指定重定向 URL (狀態碼可以為如下幾種 301,302,303,307),也可以為其他狀態碼指定響應的文字內容,並且重定向的 URL 和響應的文字可以包含變數。
Context: server, location, if
# return code [text];
location = /ok {
return 200 "ok"; # 返回 ok 給客戶端
}
# return code URL;
location = /redirect {
return 302 http://www.baidu.com; # 臨時重定向
}
# return URL;
location = /redirect {
return http://www.baidu.com; # 臨時重定向
}
4. rewrite
使用指定的正規表示式匹配請求 URL,如果匹配成功,則根據規則更改 URL。rewrite
指令按照它們在配置檔案中出現的先後順序執行。可以使用 flag
標誌來終止指令的進一步處理。如果替換字串以 http://
、https://
或 $scheme
開頭,則停止處理後續內容,並直接重定向返回給客戶端。語法:rewrite regex replacement [flag];
Context: server, location, if
# 第一種情況,帶 http://
location / {
rewrite /test1/(.*) http://www.$1.com;
return 200 "ok";
}
# 在瀏覽器中訪問,被臨時重定向到 www.baidu.com
# 後面的 return 指令將沒有機會執行了
# 第二種情況,不帶 http://
location / {
rewrite /test1/(.*) www.$1.com;
return 200 "ok";
}
# 在瀏覽器中訪問,返回了 ok
rewrite
的四個 flag
:
-
last
停止處理當前的ngx_http_rewrite_module
的指令集,並開始搜尋與更改後的 URL 相匹配的 location; -
break
停止處理當前的ngx_http_rewrite_module
指令集; -
redirect
返回 302 臨時重定向; -
permanent
返回 301 永久重定向。
location / {
# 順序執行如下兩條 rewrite 指令
# rewrite 後面沒有任何 flag 時就順序執行
# 當 location 中沒有 rewrite 模組指令可被執行時,就重寫發起新一輪 location 匹配
rewrite ^/test1 /test2;
rewrite ^/test2 /test3; # 此處發起新一輪location匹配,重寫後的 url 為 /test3
}
location = /test2 {
return 200 "/test2";
}
location = /test3 {
return 200 "/test3";
}
# 傳送如下請求
# curl 127.0.0.1:8080/test1
# /test3
location / {
rewrite ^/test1 /test2;
rewrite ^/test2 /test3 last; # 此處發起新一輪 location 匹配,重寫後的 url 為 /test3
rewrite ^/test3 /test4;
}
location = /test2 {
return 200 "/test2";
}
location = /test3 {
return 200 "/test3";
}
location = /test4 {
return 200 "/test4";
}
# 傳送如下請求
# curl 127.0.0.1:8080/test1
# /test3
location / {
rewrite ^/test1 /test2;
rewrite ^/test2 /more/index.html break; # 終止執行後續 rewrite 模組指令,重寫後的 url 為 /more/index.html
rewrite /more/index.html /test4;
proxy_pass https://www.baidu.com; # 因為 proxy_pass 不是 rewrite 模組的指令,所以它不會被 break 終止
}
# 傳送如下請求
# curl 127.0.0.1:8080/test1
# 代理到 百度產品大全頁面: https://www.baidu.com/more/index.html;
5. rewrite_log
開啟或者關閉 rewrite
模組指令的執行日誌,如果開啟,則記錄下 notice
級別的日誌到 error_log
中,預設為關閉 off
。
Context: http, server, location, if
6. set
設定指定變數的值。變數的值可以包含文字,變數或者是它們的組合形式。
Context: server, location, if
location / {
set $var1 "host is ";
set $var2 $host;
set $var3 " uri is $request_uri";
return 200 "response ok $var1$var2$var3";
}
# 傳送如下請求
# curl 127.0.0.1:8080/test
# response ok host is 127.0.0.1 uri is /test
參考文章: