openresty开发系列33--openresty执行流程之3重写rewrite和重定向
openresty開發(fā)系列33--openresty執(zhí)行流程之3重寫rewrite和重定向
重寫rewrite階段
1)重定向
2)內(nèi)部,偽靜態(tài)
先介紹一下if,rewrite指令
一)if指令
語法:if (condition){...}
默認(rèn)值:無
作用域:server,location
對(duì)給定的條件condition進(jìn)行判斷。如果為真,大括號(hào)內(nèi)的指令將被執(zhí)行。
上面的if和(之間需要留空格,否則會(huì)報(bào)錯(cuò)。
1)條件可以為一個(gè)變量
如果一個(gè)變量名進(jìn)行條件判斷,空字符串'' 或 字符串為'0',都表示為假 false
location /api {?? ?
?? ?set $a '11111';
?? ?if ($a){
?? ??? ?return 200 "11111";
?? ?}
?? ?# 如果沒有匹配到上面的就返回 200 2222222222
?? ?return 200 "2222222222";
}
2)條件為表達(dá)式
正則表達(dá)式匹配:
= ,!= 比較的一個(gè)變量和字符串
~:與指定正則表達(dá)式模式匹配時(shí)返回“真”,判斷匹配與否時(shí)區(qū)分字符大小寫;
~*:與指定正則表達(dá)式模式匹配時(shí)返回“真”,判斷匹配與否時(shí)不區(qū)分字符大小寫;
!~:與指定正則表達(dá)式模式不匹配時(shí)返回“真”,判斷匹配與否時(shí)區(qū)分字符大小寫;
!~*:與指定正則表達(dá)式模式不匹配時(shí)返回“真”,判斷匹配與否時(shí)不區(qū)分字符大小寫;
location /api {
?? ? if ($request_uri ~* "/api/[0-9]+") {
?? ??? ?return 200 "api";
?? ? }
}
3) 文件及目錄匹配判斷:
-f, !-f:判斷指定的路徑是否為存在且為文件;
-d, !-d:判斷指定的路徑是否為存在且為目錄;
-e, !-e:判斷指定的路徑是否存在,文件或目錄均可;
-x, !-x:判斷指定路徑的文件是否存在且可執(zhí)行;
location /api {
?? ? if (-f "/usr/local/lua/test.lua") {
?? ??? ?return 200 "test存在";
?? ? }
}
注意:
1)nginx if 沒有對(duì)應(yīng)的else
2)if 表達(dá)式中 是不能用? &&? ||
4)nginx的配置中不支持if條件的邏輯與&& 邏輯或|| 運(yùn)算等邏輯運(yùn)算符
?? 而且不支持if的嵌套語法,否則會(huì)報(bào)錯(cuò)。
如:
location /api {
?? ?if ( $arg_a != '1' && $arg_a != '2' ) {
?? ?? rewrite ^/(.*)$ https://www.baidu.com permanent;
?? ?}
}
會(huì)報(bào)錯(cuò)nginx: [emerg] invalid condition
修改為:
set $flag 0;
if ($arg_a != '1') {
??? set $flag "${flag}1";?? ---> 01
}
if ($arg_a != '2'){
??? set $flag "${flag}1";?? ---> 011
}
if ($flag = "011"){
??? rewrite ^/(.*)$ https://www.baidu.com permanent;
}
二)Rewrite規(guī)則
1)http status code 301 與 302區(qū)別
301 redirect: 301 代表永久性轉(zhuǎn)移(Permanently Moved)
302 redirect: 302 代表暫時(shí)性轉(zhuǎn)移(Temporarily Moved)
詳細(xì)來說,301和302狀態(tài)碼都表示重定向,就是說瀏覽器在拿到服務(wù)器返回的這個(gè)狀態(tài)碼后會(huì)自動(dòng)跳轉(zhuǎn)到一個(gè)
新的URL地址,這個(gè)地址可以從響應(yīng)的Location首部中獲取,用戶看到的效果就是他輸入的地址A瞬間變成了另一個(gè)地址B
—這是它們的共同點(diǎn)。他們的不同在于。301表示舊地址A的資源已經(jīng)被永久地移除了(這個(gè)資源不可訪問了),
搜索引擎在抓取新內(nèi)容的同時(shí)也將舊的網(wǎng)址交換為重定向之后的網(wǎng)址;302表示舊地址A的資源還在(仍然可以訪問),
這個(gè)重定向只是臨時(shí)地從舊地址A跳轉(zhuǎn)到地址B,搜索引擎會(huì)抓取新的內(nèi)容而保存舊的網(wǎng)址。
2)rewrite指令
語法rewrite regex replacement [flag];
regex:perl兼容正則表達(dá)式語句進(jìn)行規(guī)則匹配
replacement:將正則匹配的內(nèi)容替換成replacement
flag標(biāo)記:rewrite支持的flag標(biāo)記
rewrite功能就是,使用nginx提供的全局變量或自己設(shè)置的變量,結(jié)合正則表達(dá)式和標(biāo)志位實(shí)現(xiàn)url重寫以及重定向。
rewrite只能放在server{},location{},if{}中,并且只能對(duì)域名后邊的除去傳遞的參數(shù)外的字符串起作用,
例如http://www.a.com/api/index.jsp?id=1&u=str 只對(duì)api/index.jsp重寫。
正則表達(dá)式元字符:
.???? :匹配除換行符以外的任意字符
????? :重復(fù)0次或1次
+???? :重復(fù)1次或更多次
*???? :重復(fù)0次或更多次
\d??? :匹配數(shù)字
^???? :匹配字符串的開始字符
$???? :匹配字符串的結(jié)束字符
{n}?? :重復(fù)n次
{n,}? :重復(fù)n次或更多次
[c]?? :匹配單個(gè)字符c
[a-z] :匹配a-z小寫字母的任意一個(gè)
在rewrite中,如果使用小括號(hào)(),那么在小括號(hào)之間匹配的內(nèi)容,可以在后面通過$1來引用,
$2表示的是前面第二個(gè)()里的內(nèi)容
flag標(biāo)志位
last : 相當(dāng)于Apache的[L]標(biāo)記,表示完成rewrite
break : 停止執(zhí)行當(dāng)前虛擬主機(jī)的后續(xù)rewrite指令集
redirect : 返回302臨時(shí)重定向,地址欄會(huì)顯示跳轉(zhuǎn)后的地址
permanent : 返回301永久重定向,地址欄會(huì)顯示跳轉(zhuǎn)后的地址
-----------------------------------
location /foo {
? rewrite ^ /bar redirect;
}
location /bar {
? echo "bar";
}
-----------------------------------
location /api {?? ?
?? ?rewrite ^/(.*) https://www.baidu.com/s?wd=$1 permanent;
}
請(qǐng)求:http://192.168.31.150/api?? ---> $1 = api
請(qǐng)求:http://192.168.31.150/api/pro?? ---> $1 = api/pro
-----------------------------------
last 和 break 區(qū)別:
last: 停止當(dāng)前這個(gè)請(qǐng)求,并根據(jù)rewrite匹配的規(guī)則重新發(fā)起一個(gè)請(qǐng)求。新請(qǐng)求又從第一階段開始執(zhí)行…
break:相對(duì)last,break并不會(huì)重新發(fā)起一個(gè)請(qǐng)求,只是跳過當(dāng)前的rewrite階段,并執(zhí)行本請(qǐng)求后續(xù)的執(zhí)行階段…
break與last都停止處理后續(xù)rewrite指令集,不同之處在與last會(huì)重新發(fā)起新的請(qǐng)求,
而break不會(huì)。當(dāng)請(qǐng)求break時(shí),如匹配內(nèi)容存在的話,可以直接請(qǐng)求成功
案例:
location /break/ { ?
?? rewrite ^/break/(.*) /test/$1 break;? #----break;/test/$1 會(huì)在根目錄下去查找/test/$1文件,即去 /data/www/html/test/目錄下找 $1 文件
} ?
?
location /last/ { ?
?? rewrite ^/last/(.*) /test/$1 last;??? #----last;/test/$1 會(huì)重新走一遍location匹配流程
}
location /test/ { ?
?? echo "test page";
} ?
---------------------------------
偽靜態(tài)
location = /pro {
?? ?echo "pro_$arg_pid";
}
location /{
?? ?rewrite ^/product/(\d+).html$ /pro?pid=$1 last;
}
應(yīng)用場(chǎng)景:
a)可以調(diào)整用戶瀏覽的URL,看起來更規(guī)范,合乎開發(fā)及產(chǎn)品人員的需求。
b)為了讓搜索引擎搜錄網(wǎng)站內(nèi)容及用戶體驗(yàn)更好,企業(yè)會(huì)將動(dòng)態(tài)URL地址偽裝成靜態(tài)地址提供服務(wù)。
c)網(wǎng)址換新域名后,讓舊的訪問跳轉(zhuǎn)到新的域名上。例如,訪問京東的360buy.com會(huì)跳轉(zhuǎn)到j(luò)d.com
d)根據(jù)特殊變量、目錄、客戶端的信息進(jìn)行URL調(diào)整等
可應(yīng)用在server,location,if標(biāo)簽
執(zhí)行順序是:
a)執(zhí)行server塊的rewrite指令
b)執(zhí)行l(wèi)ocation匹配
c)執(zhí)行選定的location中的rewrite指令
如果其中某步URI被重寫,則重新循環(huán)執(zhí)行a-c,直到找到真實(shí)存在的文件;循環(huán)超過10次,
則返回500 Internal Server Error錯(cuò)誤。
三)rewrite_by_lua
語法:rewrite_by_lua <lua-script-str>
語境:http、server、location、location if
階段:rewrite tail
作為rewrite階段的處理,為每個(gè)請(qǐng)求執(zhí)行指定的lua代碼。注意這個(gè)處理是在標(biāo)準(zhǔn)HtpRewriteModule之后進(jìn)行的:
執(zhí)行內(nèi)部URL重寫或者外部重定向,典型的如偽靜態(tài)化的URL重寫。其默認(rèn)執(zhí)行在rewrite處理階段的最后
1) ngx.redirect ---重定向
語法:ngx.redirect(uri, status?)
該方法會(huì)給客戶端返回一個(gè)301/302重定向,具體是301還是302取決于設(shè)定的status值,
如果不指定status值,默認(rèn)是返回302
rewrite ^ /bar redirect; 等價(jià)于 ngx.redirect("https://www.baidu.com", 302)
rewrite ^ /bar permanent; 等價(jià)于 ngx.redirect("https://www.baidu.com", 301)
--------------nginx.conf配置文件
location /lua_rewrite_1 {
? rewrite_by_lua_block {
??? if ngx.req.get_uri_args()["jump"] == "1" then
????? return ngx.redirect("https://www.baidu.com", 302)
??? end
? }
? echo "no rewrite";
}
當(dāng)我們請(qǐng)求http://10.11.0.215/lua_rewrite_1時(shí)發(fā)現(xiàn)沒有跳轉(zhuǎn),
而請(qǐng)求http://10.11.0.215/lua_rewrite_1?jump=1時(shí)發(fā)現(xiàn)跳轉(zhuǎn)到百度首頁了。
此處需要 301/302跳轉(zhuǎn)根據(jù)自己需求定義。
----------------------------------------------
在取個(gè)案例
location /foo {
? set $a 12;
? set $b '';
? rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1';
? if ($b = '13') {
??? rewrite ^ /bar redirect;
??? break;
? }
? echo "res = $b";
}
location /bar {
? echo "bar";
}
因?yàn)閕f會(huì)在rewrite_by_lua之前運(yùn)行,所以判斷將不成立。正確的寫法應(yīng)該是這樣:
location /foo {
??? set $a 12;
??? set $b '';
??? rewrite_by_lua_block {
??????? ngx.var.b = tonumber(ngx.var.a) + 1
??????? if tonumber(ngx.var.b) == 13 then
??????????? return ngx.redirect("/bar");
??????? end
??? }
??? echo "res = $b";
}
----------------------------------------------
2)ngx.req.set_uri ---內(nèi)部重寫
語法: ngx.req.set_uri(uri, jump?)
通過參數(shù)uri重寫當(dāng)前請(qǐng)求的uri;參數(shù)jump,表明是否進(jìn)行l(wèi)ocations的重新匹配。
當(dāng)jump為true時(shí),調(diào)用ngx.req.set_uri后,nginx將會(huì)根據(jù)修改后的uri,重新匹配新的locations;
如果jump為false,將不會(huì)進(jìn)行l(wèi)ocations的重新匹配,而僅僅是修改了當(dāng)前請(qǐng)求的URI而已。jump的默認(rèn)值為false。
rewrite ^ /lua_rewrite_3;???????????? 等價(jià)于? ngx.req.set_uri("/lua_rewrite_3", false);
rewrite ^ /lua_rewrite_3 break;?????? 等價(jià)于? ngx.req.set_uri("/lua_rewrite_3", false);
rewrite ^ /lua_rewrite_4 last;??????? 等價(jià)于? ngx.req.set_uri("/lua_rewrite_4", true);
---------------nginx.conf配置文件
location /foo {
?? ?rewrite_by_lua_block {
?? ??? ? ngx.req.set_uri_args({a = 1, b = 2});
?? ??? ? ngx.req.set_uri("/bar/index.html", true);
?? ?}
}
location /bar {
? echo "bar uri : $uri,a : $arg_a,b : $arg_b";
}
ngx.req.set_uri_args:重寫請(qǐng)求參數(shù);
?
注意 ngx.req.set_uri(uri, true) 時(shí),ngx.req.set_uri_args的順序
轉(zhuǎn)載于:https://www.cnblogs.com/reblue520/p/11446376.html
總結(jié)
以上是生活随笔為你收集整理的openresty开发系列33--openresty执行流程之3重写rewrite和重定向的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: openresty开发系列33--ope
- 下一篇: openresty开发系列34--ope