Nginx 學習總結(4)—— Rewrite 模塊

這是 Nginx 學習總結的第四篇,上一篇介紹到了 Nginx 學習總結(3) —— Location 模塊,這一篇會對Rewrite模塊 作一些總結。根據官方文檔說明,Rewrite 模塊是用於使用 PCRE 正則表達式更改請求 URI,有條件地選擇配置,並返回重定向。php

表面看, rewritelocation 的功能有點像,都能實現跳轉,然而它們的區別在於: rewrite 是在同一域名內更改獲取資源的路徑,而 location 是對一類路徑作控制訪問或反向代理,而且能夠 proxy_pass 到其餘機器。

不少狀況下 rewrite 也會寫在 location 裏,它們的執行順序是:html

  1. 執行 server 塊的 rewrite 指令;
  2. 執行 location 匹配;
  3. 執行選定的 location 中的 rewrite 指令。
若是其中某步 URI 被重寫,則從新循環執行1-3,直到找到真實存在的文件;循環超過10次,則返回 500 Internal Server Error 錯誤。

指令

1. break

中止執行 ngx_http_rewrite_module 模塊的指令集,可是其餘模塊指令不受影響。nginx

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 中的幾種判斷條件:segmentfault

  • 一個變量名,若是變量 $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 客戶端請求的動做,一般爲 GETPOST
  • $remote_addr 客戶端的 IP 地址
  • $remote_port 客戶端的端口
  • $remote_user 已經通過 Auth Basic Module 驗證的用戶名
  • $request_filename 當前請求的文件路徑,由 rootalias 指令與 URI 請求生成
  • $scheme 請求協議,如 http,https
  • $server_protocol 請求客戶端協議,一般是 HTTP/1.0HTTP/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];cookie

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 的四個 flagcurl

  • 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

參考文章:

  1. 搞懂 nginx 的 rewrite 模塊
  2. nginx 配置 location 總結及 rewrite 規則寫法
  3. Module ngx_http_rewrite_module
相關文章
相關標籤/搜索