在軟件的發佈中,我們經常會使用到 Nginx,Nginx 的功能非常的龐雜,其中 rewrite 是一個非常常用的功能模塊,本文介紹 rewrite 的基本概念和幾個小技巧。
rewrite 是 Nginx 中的一個模塊,這個模塊用來重定向頁面,在 rewrite 模塊中包含了幾個指令來實現不同的功能:
- return
- rewrite
- if
return 指令
return 指令是 rewrite 模塊中非常常用的一個指令,可以幫助我們做重定向和一些簡單的返回。
語法
return code text;
return code URL;
return URL;
return 指令的語法由兩個或三個部分組成:
- return: 關鍵字
- code:http 狀態碼,當沒有設置 code 時,默認使用 302
- text 或 URL:返回的字符串或跳轉的地址
使用範圍
- server 節點
- location 節點
- if 塊中
- 在 server 節點中的 return 的優先級要高於 location 節點的 return,不管 return 指令寫在 location 節點的上方還是下方
- 在 return 指令中使用 code,經常會用到 301 或 302 ,區別如下:
- 301:永久重定向,例如訪問 a.com,通過 return 使用 301 重定向到了 b.com,然後修改 return 的地址爲 c.com,訪問 a.com,還是訪問的 b.com,因爲被緩存了
- 302:臨時重定向,例如訪問 a.com,通過 return 使用 302 重定向到了 b.com,然後修改 return 的地址爲 c.com,訪問 a.com,會跳轉到 c.com,不會被緩存
rewrite 指令
可以根據指定的正則表達式將用戶請求的 url 轉換成一個新的 url 進行重定向。
語法
rewrite regex replacement [flag];
return 指令的語法四個部分組成:
- rewrite: 關鍵字
- regex:正則表達式,用於匹配用戶請求的 url 地址
- replacement:新的 url 地址,當地址開頭爲 http 或 https ,默認爲 302 重定向
- flag:替換後的 url 根據 flag 進行處理,flag 有四個值
- last:使用 replacement 的地址重新進行 location 匹配
- break:會停止後面腳本的執行
- redirect:返回 302 重定向,地址欄顯示重定向後的url
- permanent:返回 301 重定向,地址欄顯示重定向後的url
使用範圍
- server 節點
- location 節點
- if 塊中
- rewrite 指令的適用範圍和 return 指令的是一致的,優先級也相同
- 當 rewrite 指令和 return 指令同時存在時,如果 rewrite 最後的 flag 不是 break,會繼續執行 rewrite 之後的 return 指令
- 沒有指定 flag 的情況下,默認爲 302 重定向
if 指令
通過 if 指令進行一些條件的判斷,然後進行 return、rewrite 或是其他的一些處理。
語法
if(condition){
}
使用範圍
- server 節點
- location 節點
if 判斷的一些規則
- 變量和字符串做比較,使用 = 或 !=
- 將變量和正則表達式做比較:
- 大小寫敏感:~ 或 !~
- 大小寫不敏感:~* 或 !~* ,例如上圖中的示例
- 檢查文件是否存在,使用 -f 或 !-f
- 檢查目錄是否存在,使用 -d 或 !-d
示例
下面以近期用到的兩個場景來演示實際的用法。
PC 端跳轉到移動端
場景描述:
- PC 端發佈後的地址爲:192.168.0.1
- 移動端採用 H5 開發,發佈後的地址:192.168.0.1:81
- 在手機上訪問 PC 端地址,跳轉到移動端
- PC 端和移動端使用同一個接口地址,接口地址是在 PC 端使用 /api 進行的代理
- 只有頁面的請求跳轉到移動端,接口的請求不需要跳轉
配置如下:
server {
listen 80;
server_name localhost;
set $flag 0;
if ($http_user_agent ~* (mobile|nokia|iphone|ipad|android|samsung|htc|blackberry) ) {
set $flag "${flag}1";
}
if ($request_uri !~* /api/) {
set $flag "${flag}2";
}
if ($flag = "012") {
rewrite ^(.*) http://192.168.0.1:81? permanent;
}
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location /api/ {
proxy_pass http://192.168.0.1:5000/;
}
error_page 500 502 503 504 /50x.html;
}
- 兩個條件都滿足的情況下,進行跳轉
- 設備類型爲移動端
- 請求的路由中不包含 /api
- 因爲 if 指令的條件的限制,不能再一個 condition 中使用多條件,所以定義了一個變量 $flag 來做判斷
將源地址中的特定參數傳遞到目標地址
場景描述:
- 上面的示例中,跳轉到移動端後進入的是移動端的登錄頁面,因爲沒有登錄人的身份
- 現在假設 PC 端的地址後有 authcode 的參數用來確定身份,除此之外還有其他的參數,例如:
http://192.168.0.1?id=xxxxx&authcode=xxxxxxxx
- 需要再跳轉後將 authcode 傳遞到移動端的地址後面,例如:
http://192.168.0.1:81?authcode=xxxxxxxx
移動端可以做解析實現直接登錄
配置如下: