溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Last 與 break flag的區(qū)別是什么

發(fā)布時(shí)間:2021-11-09 16:00:57 來(lái)源:億速云 閱讀:111 作者:柒染 欄目:建站服務(wù)器

Last 與 break flag的區(qū)別是什么,針對(duì)這個(gè)問(wèn)題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問(wèn)題的小伙伴找到更簡(jiǎn)單易行的方法。

Rewrite( URL 重寫(xiě))指令可以出現(xiàn)在 server{} 下,也可以出現(xiàn)在 location{} 下,它們之間是有區(qū)別的!對(duì)于出現(xiàn)在 server{} 下的 rewrite 指令,它的執(zhí)行會(huì)在 location 匹配之前;對(duì)于出現(xiàn)在 location{} 下的 rewrite 指令,它的執(zhí)行當(dāng)然是在 location 匹配之后,但是由于 rewrite 導(dǎo)致 HTTP 請(qǐng)求的 URI 發(fā)生了變化,所以 location{} 下的 rewrite 后的 URI 又需要重新匹配 location ,就好比一個(gè)新的 HTTP 請(qǐng)求一樣(注意由 location{} 內(nèi)的 rewrite 導(dǎo)致的這樣的循環(huán)匹配最多不超過(guò) 10 次,否則 nginx 會(huì)報(bào) 500 錯(cuò)誤)??偟膩?lái)說(shuō),如果 server{} 和 location{} 下都有 rewrite ,依然是先執(zhí)行 server{} ,然后進(jìn)行 location 匹配,如果被匹配的 location{} 之內(nèi)還有 rewrite 指令,那么繼續(xù)執(zhí)行 rewrite ,同時(shí)因?yàn)?location{} 內(nèi)的 rewrite 改變了 URI ,那么重寫(xiě)后的結(jié)果 URI 需要當(dāng)做一個(gè)新的請(qǐng)求,重新匹配 location (應(yīng)該也包括重新執(zhí)行 server{} 下的 rewrite 吧)。

Last 與 break flag 的區(qū)別

關(guān)于 last flag 和 break flag 的區(qū)別,官方文檔的描述是:“ last - completes processing of rewrite directives, after which searches for corresponding URI and location ”和“ break - completes processing of rewrite directives ”,都有“不讓繼續(xù)執(zhí)行后面的 rewrite 指令”的含義,但是兩者的區(qū)別并沒(méi)有展開(kāi)。

這里我用實(shí)驗(yàn)來(lái)告訴大家區(qū)別。實(shí)驗(yàn)準(zhǔn)備:

1、  安裝 nginx ;(如果對(duì)安裝和 location 不了解的,請(qǐng)參考:http://eyesmore.iteye.com/blog/1141660 )

2、  在 nginx 安裝目錄的 html 子目錄下創(chuàng)建 4 個(gè)文件,分別叫: aaa.html , bbb.html , ccc.html 和 ddd.html ,文件內(nèi)容分別是各自的文件名(例 aaa.html 文件內(nèi)容不妨寫(xiě) aaa html file )。

3、  Nginx 配置文件初始化是:

error_log  logs/error.log info;  #URL 重寫(xiě)模塊的日志會(huì)寫(xiě)入此文件

   server {

        listen       9090;

        server_name  localhost;

        root html;

        rewrite_log on;   # 打開(kāi) URL 重寫(xiě)模塊的日志開(kāi)關(guān),以便寫(xiě)入 error_log

        location  /aaa.html {

            rewrite "^/aaa\.html$"  /bbb.html;

            rewrite "^/bbb\.html$"  /ddd.html;

        }  

        location  /bbb.html {

            rewrite "^/bbb\.html$" /ccc.html;

        }  

}

上述配置注意兩點(diǎn): 1 、打開(kāi) rewrite 模塊的日志開(kāi)關(guān),以便 rewrite 執(zhí)行日志寫(xiě)入 error_log (注: rewrite 日志寫(xiě)入 error_log 的級(jí)別是 notice ,所以要注意 error_log 日志級(jí)別,此處用 info ); 2 、定義了兩個(gè) location ,分別是 /aaa.html 和 /bbb.html ,但是在 /aaa.html 中,把 /aaa.html 重寫(xiě)成 /bbb.html ,接著又把 /bbb.html 重寫(xiě)成 /ddd.html ;在 /bbb.html 中,把 /bbb.html 重寫(xiě)成 /ccc.html 。

[ 測(cè)試 1] 沒(méi)有 last 和 break 標(biāo)記時(shí):請(qǐng)求 aaa.html

[root@web108 ~]# curl http://localhost:9090/aaa.html

ddd html file

[root@web108 ~]#

Error_log 的日志內(nèi)容:

2011/08/07 22:13:23 [notice] 9066#0: *85 "^/aaa\.html$" matches "/aaa.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/07 22:13:23 [notice] 9066#0: *85 rewritten data: "/bbb.html" , args: "", client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/07 22:13:23 [notice] 9066#0: *85 "^/bbb\.html$" matches "/bbb.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/07 22:13:23 [notice] 9066#0: *85 rewritten data: "/ddd.html" , args: "", client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/07 22:13:23 [info] 9066#0: *85 client 127.0.0.1 closed keepalive connection

URL 重寫(xiě)模塊的日志告訴我們:對(duì)于一個(gè) HTTP 請(qǐng)求“ GET /aaa.html ”,重寫(xiě)過(guò)程是:先 /aaa.html 被重寫(xiě)為 /bbb.html ;然后 rewritten data: /bbb.html ,繼續(xù)執(zhí)行后面的 rewrite 指令,進(jìn)而被重寫(xiě)為 /ddd.html ,然后 rewrittern data: /ddd.html 后面沒(méi)有重寫(xiě)了(其實(shí)此時(shí) /ddd.html 需要再次重新匹配 location 的,只是日志沒(méi)有體現(xiàn)出來(lái),接下來(lái)的測(cè)試 2 會(huì)體現(xiàn)這點(diǎn)),于是輸出 /ddd.html 的內(nèi)容。

[ 測(cè)試 2] 使用 last 標(biāo)記時(shí):請(qǐng)求 aaa.html

將上述 location /aaa.html {} 修改成:

location  /aaa.html {

       rewrite "^/aaa\.html$"  /bbb.html   last ;

      rewrite "^/bbb\.html$"  /ddd.html;

}  

測(cè)試結(jié)果:

[root@web108 ~]# curl http://localhost:9090/aaa.html

ccc html file

[root@web108 ~]#

Error_log 日志:

2011/08/07 22:24:31 [notice] 18569#0: *86 "^/aaa\.html$" matches "/aaa.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/07 22:24:31 [notice] 18569#0: *86 rewritten data: "/bbb.html" , args: "", client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/07 22:24:31 [notice] 18569#0: *86 "^/bbb\.html$" matches "/bbb.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/07 22:24:31 [notice] 18569#0: *86 rewritten data: "/ccc.html" , args: "", client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/07 22:24:31 [info] 18569#0: *86 client 127.0.0.1 closed keepalive connection

不知道讀者看到 GET /aaa.html 顯示的結(jié)果“ ccc html file ”會(huì)不會(huì)驚訝:“為什么結(jié)果不是 bbb html file ”。下面解釋下整個(gè)過(guò)程:首先 /aaa.html 匹配了 location /aaa.html {} ,于是執(zhí)行 rewrite "^/aaa\.html$"  /bbb.html last ,把 /aaa.html 重寫(xiě)為 /bbb.html ,同時(shí)由于 last flag 的使用,后面的 rewrite 指令(指的是 rewrite "^/bbb\.html$"  /ddd.html )不會(huì)被執(zhí)行。似乎此時(shí)應(yīng)該輸出“ bbb html file ”才對(duì),但是我們看看 nginx 官方解釋?zhuān)骸?last - completes processing of rewrite directives, after which searches for corresponding URI and location ”意思是說(shuō) last 不再匹配后面的 rewrite 指令,但是緊接著需要對(duì)重寫(xiě)后的 URI 重新匹配 location 。讓我們?cè)倏纯垂俜降摹?If the directives of this module are given at the server level, then they are carried out before the location of the request is determined. If in that selected location there are further rewrite directives, then they also are carried out. If the URI changed as a result of the execution of directives inside location, then location is again determined for the new URI. This cycle can be repeated up to 10 times, after which Nginx returns a 500 error. ”因此,重新匹配的時(shí)候,匹配到了新的 location /bbb.html {} ,執(zhí)行“ rewrite "^/bbb\.html$" /ccc.html ”,最后的內(nèi)容是“ ccc html file ”。

[ 測(cè)試 3] 使用 break 標(biāo)記時(shí):請(qǐng)求 aaa.html

將上述 location /aaa.html {} 修改成使用 break 標(biāo)記:

location  /aaa.html {

      rewrite "^/aaa\.html$"  /bbb.html  break ;

      rewrite "^/bbb\.html$"  /ddd.html;

}  

測(cè)試結(jié)果:

[root@web108 ~]# curl http://localhost:9090/aaa.html

bbb html file

[root@web108 ~]#

日志結(jié)果:

2011/08/07 22:37:49 [notice] 21069#0: *89 "^/aaa\.html$" matches "/aaa.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/07 22:37:49 [notice] 21069#0: *89 rewritten data: "/bbb.html" , args: "", client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/07 22:37:49 [info] 21069#0: *89 client 127.0.0.1 closed keepalive connection

我想這個(gè)結(jié)果不用多做解釋了,充分體現(xiàn)了 break 和 last 的區(qū)別:“ last - completes processing of rewrite directives, after which searches for corresponding URI and location ”和“ break - completes processing of rewrite directives ”。 Break 和 last 都能阻止繼續(xù)執(zhí)行后面的 rewrite 指令,但是 last 如果在 location 下用的話,對(duì)于重寫(xiě)后的 URI 會(huì)重新匹配 location ,但是 break 則不會(huì)重新匹配 location 。簡(jiǎn)單的說(shuō), break 終止的力度比 last 更加徹底(為了記憶的方便,我們可以把重新后的 URI 重新匹配 location 理解為“ URI 匹配 location 的循環(huán)語(yǔ)句的下一次迭代”,高級(jí)程序設(shè)計(jì)里面 break 一般用做退出循環(huán),所以 break 不僅終止繼續(xù)執(zhí)行 rewrite ,而且退出 URI 重新匹配 location 的循環(huán)迭代)。

Nginx 關(guān)于 Rewrite 的迭代 第二篇

例題 1

配置:

error_log  logs/error.log info;

server {

        listen       9090;

        server_name  localhost;

        root html;

        rewrite_log on;

        rewrite "^/aaa\.html$"  /bbb.html;

        location  /ccc.html {

            rewrite "^/ccc\.html$"  /eee.html;

        }

        location  /bbb.html {

            rewrite "^/bbb\.html$" /ccc.html;

            rewrite "^/ccc\.html$" /ddd.html;

        }  

}   

結(jié)果:

[root@web108 ~]# curl http://localhost:9090/aaa.html

ddd html file

[root@web108 ~]#

日志:

2011/08/08 10:05:41 [notice] 31592#0: *90 "^/aaa\.html$" matches "/aaa.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/08 10:05:41 [notice] 31592#0: *90 rewritten data: "/bbb.html" , args: "", client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/08 10:05:41 [notice] 31592#0: *90 "^/bbb\.html$" matches "/bbb.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/08 10:05:41 [notice] 31592#0: *90 rewritten data: "/ccc.html" , args: "", client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/08 10:05:41 [notice] 31592#0: *90 "^/ccc\.html$" matches "/ccc.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/08 10:05:41 [notice] 31592#0: *90 rewritten data: "/ddd.html" , args: "", client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/08 10:05:41 [notice] 31592#0: *90 "^/aaa\.html$" does not match "/ddd.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/08 10:05:41 [info] 31592#0: *90 client 127.0.0.1 closed keepalive connection

解釋?zhuān)?/p>

GET /aaa.html 請(qǐng)求,首先執(zhí)行 server 級(jí)的 rewrite 指令,被重寫(xiě)為 /bbb.html ,然后匹配到 location /bbb.html {} ,接著執(zhí)行 location 級(jí)的 rewrite 指令,先重寫(xiě)為 /ccc.html ,再重寫(xiě)為 /ddd.html ;由于 URI 被 location 級(jí)的 rewrite 指令重寫(xiě)了,因此需要重新進(jìn)行 location 的匹配,相當(dāng)于重寫(xiě)后的 URI 被當(dāng)做一個(gè)新的請(qǐng)求,會(huì)重新執(zhí)行 server 級(jí)的 rewrite ,然后重新匹配 location ,日志“ 2011/08/08 10:05:41 [notice] 31592#0: *90 "^/aaa\.html$" does not match "/ddd.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090" ”體現(xiàn)了重新匹配 location 的流程。

例題 2

配置:

error_log  logs/error.log info;

server {

        listen       9090;

        server_name  localhost;

        root html;

        rewrite_log on;

        rewrite "^/aaa\.html$"  /bbb.html;

                   rewrite "^/ccc\.html$"  /ddd.html;

        location  /bbb.html {

            rewrite "^/bbb\.html$" /ccc.html;

        }  

                   location  /ddd.html {

             rewrite "^/ddd\.html$" /eee.html;

        }

}   

結(jié)果:

[root@web108 ~]# curl http://localhost:9090/aaa.html

eee html file

[root@web108 ~]#

日志:

2011/08/08 10:21:00 [notice] 2218#0: *91 "^/aaa\.html$" matches "/aaa.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/08 10:21:00 [notice] 2218#0: *91 rewritten data: "/bbb.html" , args: "", client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/08 10:21:00 [notice] 2218#0: *91 "^/ccc\.html$" does not match "/bbb.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/08 10:21:00 [notice] 2218#0: *91 "^/bbb\.html$" matches "/bbb.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/08 10:21:00 [notice] 2218#0: *91 rewritten data: "/ccc.html" , args: "", client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/08 10:21:00 [notice] 2218#0: *91 "^/aaa\.html$" does not match "/ccc.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/08 10:21:00 [notice] 2218#0: *91 "^/ccc\.html$" matches "/ccc.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/08 10:21:00 [notice] 2218#0: *91 rewritten data: "/ddd.html" , args: "", client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/08 10:21:00 [notice] 2218#0: *91 "^/ddd\.html$" matches "/ddd.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/08 10:21:00 [notice] 2218#0: *91 rewritten data: "/eee.html" , args: "", client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/08 10:21:00 [notice] 2218#0: *91 "^/aaa\.html$" does not match "/eee.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/08 10:21:00 [notice] 2218#0: *91 "^/ccc\.html$" does not match "/eee.html" , client: 127.0.0.1, server: localhost, request: "GET /aaa.html HTTP/1.1", host: "localhost:9090"

2011/08/08 10:21:00 [info] 2218#0: *91 client 127.0.0.1 closed keepalive connection

解釋?zhuān)?/p>

第一次迭代 location 匹配

GET /aaa.html ,首先執(zhí)行 server 級(jí)的重寫(xiě),“ rewrite "^/aaa\.html$"  /bbb.html ”把 /aaa.html 重寫(xiě)為 /bbb.html ,但 /bbb.html 沒(méi)匹配上“ rewrite "^/ccc\.html$"  /ddd.html ”,最終保留 /bbb.html ;接著,匹配 location /bbb.html {} ,執(zhí)行 location 級(jí)的 rewrite 指令,把 /bbb.html 重寫(xiě)為 /ccc.html ,由于 URI 被 location 級(jí) rewrite 重寫(xiě),因此需要重新迭代 location 匹配。

第二次迭代 location 匹配

對(duì)于第一次迭代結(jié)果 /ccc.html ,首先依然是執(zhí)行 server 級(jí)的 rewrite 指令,“ rewrite "^/aaa\.html$"  /bbb.html; ”跟 /ccc.html 不匹配,但“ rewrite "^/ccc\.html$"  /ddd.html; ”把 /ccc.html 重寫(xiě)為 /ddd.html ; server 級(jí) rewrite 執(zhí)行完后,接著 location 匹配, /ddd.html 匹配到 location /ddd.html {} ,執(zhí)行 location 級(jí)的 rewrite 指令,把 /ddd.html 重寫(xiě)為 /eee.html 。同樣由于 URI 被 location 級(jí)的 rewrite 指令重寫(xiě),于是需要重新迭代 location 匹配。

第三次迭代 location 匹配

對(duì)于第二次迭代結(jié)果 /eee.html ,首先依然執(zhí)行 server 級(jí)的 rewrite 指令,“ rewrite "^/aaa\.html$"  /bbb.html; ”和“ rewrite "^/ccc\.html$"  /ddd.html; ”,只不過(guò)它們都沒(méi)匹配上 /eee.html ,接著 /eee.html 進(jìn)行 location 匹配,也沒(méi)有,最終結(jié)果是 /eee.html ,返回“ eee html file ”頁(yè)面。

最后說(shuō)明下,如果把上述配置修改成server級(jí)rewrite和location的編輯順序調(diào)整:

server {
        listen       9090;
        server_name  localhost;
        root html;
        rewrite_log on;

               
        location  /bbb.html {
            rewrite "^/bbb\.html$" /ccc.html;
        }   
        location  /ddd.html {
            rewrite "^/ddd\.html$" /eee.html;
        }

        rewrite "^/aaa\.html$"  /bbb.html;
        rewrite "^/ccc\.html$"  /ddd.html;
}

結(jié)果是不會(huì)受影響的,也就是說(shuō)location匹配迭代總是先執(zhí)行server級(jí)rewrite,再進(jìn)行l(wèi)ocation匹配,再執(zhí)行l(wèi)ocation級(jí)的rewrite,如果URI因location級(jí)rewrite指令重寫(xiě),則需要進(jìn)行下一次迭代。但總的迭代次數(shù)不超過(guò)10次,否則nginx報(bào)500錯(cuò)誤。

簡(jiǎn)單偽代碼描述下rewrite執(zhí)行過(guò)程:

boolean match_finish = false;
int match_count = 0;
while(!match_finish && match_count < 10) {
        match_count ++;
    (1)按編輯順序執(zhí)行server級(jí)的rewrite指令;
    (2)按重寫(xiě)后的URI匹配location;
    (3)
        String uri_before_location = uri;
        按編輯順序執(zhí)行l(wèi)ocation級(jí)的rewrite指令;
        String uri_after_location = rewrite(uri);
        if(uri_before_location != uri_after_location) {
            match_finish = false;            
        } else {
            match_finish = true;
        }
        if(location rewrite has last flag) {
            continue;//表示不執(zhí)行后面的rewrite,直接進(jìn)入下一次迭代
        }
        if(location rewrite has break flag) {
            break;//表示不執(zhí)行后面的rewrite,并退出循環(huán)迭代
        }
}
if(match_count <= 10) {
    return HTTP_200;
} else {
    return HTTP_500;
}

關(guān)于Last 與 break flag的區(qū)別是什么問(wèn)題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒(méi)有解開(kāi),可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI