一文理清 nginx 中的 rewrite 配置(系列二)

nginx01.png

nginx 配置 系列文章(持續更新中...)
一文理清 nginx 中的 location 配置(系列一)javascript

前言

nginx 經過 ngx_http_rewrite_module 模塊支持 URI 重寫、支持 if 條件判斷,但不支持 else。php

rewrite 只能放在 server { }location { }if { } 中,而且只能對域名後邊的除去傳遞的參數外的字符串起做用,例如http://aaa.com/a/we/index.php?id=1&u=str只對/a/we/index.php重寫。語法爲 rewrite regex replacement [flag];html

指令執行順序

表面看 rewrite 和 location 功能有點像,都能實現跳轉,主要區別在於 rewrite 是在同一域名內更改獲取資源的路徑,而 location 是對一類路徑作控制訪問或反向代理,能夠 proxy_pass 到其餘機器。不少狀況下 rewrite 也會寫在 location 裏,它們的執行順序是:前端

  1. 執行 server 塊的 rewrite 指令(這裏的塊指的是 server 關鍵字後{}包圍的區域,其它 xx 塊相似)
  2. 執行location匹配
  3. 執行選定的location中的rewrite指令

若是其中某步 URI 被重寫,則從新循環執行1-3,直到找到真實存在的文件;
若是循環超過 10 次,則返回 500 Internal Server Error 錯誤。java

指令詳解

if 指令

語法:if(condition) {…}
做用域: serverlocation
功能:對給定的條件 condition 進行判斷。若是爲真,大括號內的 rewrite 指令將被執行。if 條件 (conditon) 能夠是以下任何內容:
if 中的幾種判斷條件nginx

  • 一個變量名;false 若是這個變量是空字符串或者以0開始的字符串;
  • 使用 =!= 比較的一個變量和字符串
  • 是用 ~~* 與正則表達式匹配的變量,若是這個正則表達式中包含},;則整個表達式須要用」 或’ 包圍
  • 使用 -f!-f 檢查一個文件是否存在
  • 使用 -d!-d 檢查一個目錄是否存在
  • 使用 -e!-e 檢查一個文件、目錄、符號連接是否存在
  • 使用 -x !-x 檢查一個文件是否可執行

示例:面試

set $variable "0"; 
if ($variable) {
    # 不會執行,由於 "0" 爲 false
    break;            
}

# 使用變量與正則表達式匹配 沒有問題
if ( $http_host ~ "^star\.igrow\.cn$" ) {
    break;            
}

# 字符串與正則表達式匹配 報錯
if ( "star" ~ "^star\.igrow\.cn$" ) {
    break;            
}
# 檢查文件類的 字符串與變量都可
if ( !-f "/data.log" ) {
    break;            
}

if ( !-f $filename ) {
    break;            
}

return 指令

語法:
return code [text];
return code URL;
return URL;
做用域:serverlocationif
功能:中止處理並將指定的 code 碼返回給客戶端。 非標準 code 碼 444 關閉鏈接而不發送響應報頭。正則表達式

該指令用於檢查一個條件是否符合,若是條件符合,則執行大括號內的語句。If 指令不支持嵌套,不支持多個條件 && 和 || 處理。segmentfault

從0.8.42版本開始, return 語句能夠指定重定向 URI (狀態碼能夠爲以下幾種 301,302,303,307),瀏覽器

也能夠爲其餘狀態碼指定響應的文本內容,而且重定向的 URI 和響應的文本能夠包含變量。

有一種特殊狀況,就是重定向的url能夠指定爲此服務器本地的 URI,這樣的話,nginx 會依據請求的協議 $schemeserver_name_in_redirectport_in_redirect 自動生成完整的 URI。

示例:若是訪問的 URI 以 .sh.bash 結尾,則返回 403 狀態碼

location ~ .*\.(sh|bash)?$
{
   return 403;
}

rewrite 指令

語法:rewrite regex replacement [flag];
做用域:serverlocationif
功能:若是一個URI匹配指定的正則表達式regex,URI就按照 replacement 重寫。

rewrite 按配置文件中出現的順序執行。可使用 flag 標誌來終止指令的進一步處理。

若是 replacement 以 http://https://$ scheme 開始,將再也不繼續處理,這個重定向將返回給客戶端。

示例:第一種狀況,重寫的字符串帶 http://

location ^~ /redirect {
    # 當匹配前綴表達式 /redirect/(.*)時 請求將被臨時重定向到 http://www.$1.com
    # 至關於 flag 寫爲 redirect
    rewrite ^/(.*)$ http://www.$1.com;
    return 200 "ok";
}

在瀏覽器中輸入 127.0.0.1:8080/redirect/baidu ,則臨時重定向到 www.baidu.com 後面的 return 指令將沒有機會執行了。

location ^~ /redirect {
    rewrite ^/(.*)$ www.$1.com;
    return 200 "ok";
}
# 發送請求以下
# curl 127.0.0.1:8080/redirect/baidu
# ok

此處沒有帶 http:// 因此只是簡單的重寫。請求的 URI 由 /test1/baidu 重寫爲 www.baidu.com 由於會順序執行 rewrite 指令,因此 下一步執行 return 指令,響應後返回 ok

flag 有四種參數能夠選擇:

  1. last 中止處理後續 rewrite 指令集,而後對當前重寫的新 URI 在 rewrite 指令集上從新查找。
  2. break 中止處理後續 rewrite 指令集,並再也不從新查找,可是當前location 內剩餘非 rewrite 語句和 location 外的 非rewrite 語句能夠執行。
  3. redirect 若是 replacement 不是以 http://https:// 開始,返回 302 臨時重定向
  4. permanent 返回 301 永久重定向

示例 1:

# rewrite 後面沒有任何 flag 時就順序執行 
# 當 location 中沒有 rewrite 模塊指令可被執行時 就重寫發起新一輪location 匹配
location / {
    # 順序執行以下兩條rewrite指令 
    rewrite ^/test1 /test2;
    rewrite ^/test2 /test3;  # 此處發起新一輪 location 匹配 URI爲/test3
}

location = /test2 {
    return 200 「/test2」;
}  

location = /test3 {
    return 200 「/test3」;
}
# 發送以下請求
# curl 127.0.0.1:8080/test1
# /test3

若是正則表達regex式中包含 「}」 或 「;」,那麼整個表達式須要用雙引號或單引號包圍。

示例 2:

location / {
    rewrite ^/test1 /test2;
    rewrite ^/test2 /test3 last;  # 此處發起新一輪location匹配 uri爲/test3
    rewrite ^/test3 /test4;
    proxy_pass http://www.baidu.com;
}

location = /test2 {
    return 200 "/test2";
}  

location = /test3 {
    return 200 "/test3";
}
location = /test4 {
    return 200 "/test4";
}

發送以下請求 curl 127.0.0.1:8080/test1 返回 /test3

當若是將上面的 location / 改爲以下代碼

location / {
    rewrite ^/test1 /test2;
    # 此處不會發起新一輪location匹配;當是會終止執行後續rewrite模塊指令重寫後的 URI 爲 /more/index.html
    rewrite ^/test2 /more/index.html break;  
    rewrite /more/index\.html /test4; # 這條指令會被忽略

    # 由於 proxy_pass 不是rewrite模塊的指令 因此它不會被 break終止
    proxy_pass https://www.baidu.com;
}

發送請求 127.0.0.1:8080/test1
代理到 https://www.baidu.com

rewrite 後的請求參數:
若是替換字符串 replacement 包含新的請求參數,則在它們以後附加先前的請求參數。若是你不想要以前的參數,則在替換字符串 replacement 的末尾放置一個問號,避免附加它們。

# 因爲最後加了個 ?,原來的請求參數將不會被追加到 rewrite 以後的 URI 後面*
rewrite ^/users/(.*)$ /show?user=$1? last;

rewrite_log 指令

語法:rewrite_log on | off;
默認值:rewrite_log off;
做用域:httpserverlocationif
功能:開啓或關閉以 notice 級別打印 rewrite 處理日誌到 error log 文件。

set 指令

語法:set variable value;
默認值:none
做用域:serverlocationif
定義一個變量並賦值,值能夠是文本,變量或者文本變量混合體。

uninitialized_variable_warn 指令

做用域:httpserverlocationif
語法:uninitialized_variable_warn on | off;
默認值:uninitialized_variable_warn on
功能:控制是否記錄 有關未初始化變量的警告。

結語

本文參考/引用:
nginx配置location總結及rewrite規則寫法 - Sean’s Notes - 思否
nginx rewrite 指令 - nginx 中文手冊
nginx配置location總結及rewrite規則寫法 - seanlook - 思否

推薦閱讀:
【專題:JavaScript進階之路】
一文理清nginx中的location配置(系列一)
JavaScript中各類源碼實現(前端面試筆試必備)
深刻理解 ES6 Promise
前端性能優化小結(面試乾貨)
ES6 尾調用和尾遞歸


我是Cloudy,現居上海,一隻勤勞的前端攻城獅,愛專研,愛技術,愛分享。
我的筆記,整理不易,再次感謝 閱讀點贊收藏關注
文章有任何問題歡迎你們指出,也歡迎你們一塊兒交流學習!
相關文章
相關標籤/搜索