<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    Nginx 配置指令的執行順序(三)

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    如前文所述,除非像 ngx_set_misc 模塊那樣使用特殊技術,其他模塊的配置指令即使是在 rewrite 階段運行,也不能和 ngx_rewrite 模塊的指令混合使用。不妨來看幾個這樣的例子。

     

        第三方模塊 ngx_headers_more 提供了一系列配置指令,用于操縱當前請求的請求頭和響應頭。其中有一條名叫 more_set_input_headers 的指令可以在 rewrite 階段改寫指定的請求頭(或者在請求頭不存在時自動創建)。這條指令總是運行在 rewrite 階段的末尾,該指令的文檔中有這么一行標記:

        phase: rewrite tail

    其中的 rewrite tail 的意思就是 rewrite 階段的末尾。

     

        既然運行在 rewrite 階段的末尾,那么也就總是會運行在 ngx_rewrite 模塊的指令之后,即使我們在配置文件中把它寫在前面,例如:

        ? location /test {
        ?     set $value dog;
        ?     more_set_input_headers "X-Species: $value";
        ?     set $value cat;
        ?
        ?     echo "X-Species: $http_x_species";
        ? }

    這個例子用到的 $http_XXX 內建變量在讀取時會返回當前請求中名為 XXX 的請求頭,我們在 Nginx 變量漫談(二) 中曾經簡單提過它。需要注意的是,$http_XXX 變量在匹配請求頭時會自動對請求頭的名字進行歸一化,即將名字的大寫字母轉換為小寫字母,同時把間隔符(-)替換為下劃線(_),所以變量名$http_x_species 才得以成功匹配 more_set_input_headers 語句中設置的請求頭 X-Species.

     

        此例書寫的指令順序會誤導我們認為 /test 接口輸出的 X-Species 頭的值是 dog,然而實際的結果卻并非如此:

        $ curl 'http://localhost:8080/test'
        X-Species: cat

    顯然,寫在 more_set_input_headers 指令之后的 set $value cat 語句卻先執行了。

     

        上面這個例子證明了即使運行在同一個請求處理階段,分屬不同模塊的配置指令也可能會分開獨立運行(除非像 ngx_set_misc 等模塊那樣針對 ngx_rewrite 模塊提供特殊支持)。換句話說,在單個請求處理階段內部,一般也會以 Nginx 模塊為單位進一步地劃分出內部子階段。

     

        第三方模塊 ngx_lua 提供的 rewrite_by_lua 配置指令也和 more_set_input_headers 一樣運行在rewrite 階段的末尾。我們來驗證一下:

        ? location /test {
        ?     set $a 1;
        ?     rewrite_by_lua "ngx.var.a = ngx.var.a + 1";
        ?     set $a 56;
        ?
        ?     echo $a;
        ? }

    這里我們在 rewrite_by_lua 語句內聯的 Lua 代碼中對 Nginx 變量 $a 進行了自增計算。從該例的指令書寫順序上看,我們或許會期望輸出是 56,可是因為 rewrite_by_lua 會在所有的 set 語句之后執行,所以結果是57

        $ curl 'http://localhost:8080/test'
        57

    顯然,rewrite_by_lua 指令的行為不同于我們前面在 (二) 中介紹過的 set_by_lua 指令。

     

        有的讀者可能要問,既然 more_set_input_headers 和 rewrite_by_lua 指令都運行在 rewrite 階段的末尾,那么它們之間的先后順序又是怎樣的呢?答案是:不一定。我們應當避免寫出依賴它們二者間順序的配置。

     

        Nginx 的 rewrite 階段是一個比較早的請求處理階段,這個階段的配置指令一般用來對當前請求進行各種修改(比如對 URI 和 URL 參數進行改寫),或者創建并初始化一系列后續處理階段可能需要的 Nginx 變量。當然,也不能阻止一些用戶在 rewrite 階段做一系列更復雜的事情,比如讀取請求體,或者訪問數據庫等遠方服務,畢竟有 rewrite_by_lua 這樣的指令可以嵌入任意復雜的 Lua 代碼。

     

        在 rewrite 階段之后,有一個名叫 access 的請求處理階段。Nginx 變量漫談(五) 中介紹過的第三方模塊 ngx_auth_request 的指令就運行在 access 階段。在 access 階段運行的配置指令多是執行訪問控制性質的任務,比如檢查用戶的訪問權限,檢查用戶的來源 IP 地址是否合法,諸如此類。

     

        例如,標準模塊 ngx_access 提供的 allow 和 deny 配置指令可用于控制哪些 IP 地址可以訪問,哪些不可以:

        location /hello {
            allow 127.0.0.1;
            deny all;
     
            echo "hello world";
        }

    這個 /test 接口被配置為只允許從本機(IP 地址為保留的 127.0.0.1)訪問,而從其他 IP 地址訪問都會被拒(返回 403 錯誤頁)。ngx_access 模塊自己的多條配置指令之間是按順序執行的,直到遇到第一條滿足條件的指令就不再執行后續的 allow 和 deny 指令。如果首先匹配的指令是 allow,則會繼續執行后續其他模塊的指令或者跳到后續的處理階段;而如果首先滿足的是 deny 則會立即中止當前整個請求的處理,并立即返回 403錯誤頁。所以看上面這個例子,如果是從本地訪問的,則首先匹配 allow 127.0.0.1 這一條語句,于是 Nginx 就繼續往下執行其他模塊的指令以及后續的處理階段;而如果是從其他機器訪問,則首先匹配的則是 deny all這一條語句,即拒絕所有地址,它會導致 403 錯誤頁立即返回給客戶端。

     

        我們來實測一下。從本機訪問這個接口可以得到

        $ curl 'http://localhost:8080/hello'
        hello world

    而從另一臺機器訪問這臺機器(假設運行 Nginx 的機器地址是 192.168.1.101)提供的接口時則得到

        $ curl 'http://192.168.1.101:8080/hello'
        <html>
        <head><title>403 Forbidden</title></head>
        <body bgcolor="white">
        <center><h1>403 Forbidden</h1></center>
        <hr><center>nginx</center>
        </body>
        </html>

    值得一提的是,ngx_access 模塊還支持所謂的“CIDR 記法”來表示一個網段,例如 169.200.179.4/24 則表示路由前綴是 169.200.179.0(或者說子網掩碼是 255.255.255.0)的網段。

     

        因為 ngx_access 模塊的指令運行在 access 階段,而 access 階段又處于 rewrite 階段之后,所以前面我們見到的所有那些在 rewrite 階段運行的配置指令,都總是在 allow 和 deny 之前執行,而無論它們在配置文件中的書寫順序是怎樣的。所以,為了避免閱讀配置時的混亂,我們應該總是讓指令的書寫順序和它們的實際執行順序保持一致。

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全