nginx phases 介紹

來源:互聯網
上載者:User
一、nginx的11個phases

一個請求經過nginx處理的過程中,會經過一系列的階段(phases),下面這個表格列出了nginx的所有phases,每個階段可選的退出方式,包含的模組和對應的指令

phase optional exits modules / directives description
NGX_HTTP_POST_READ_PHASE HttpRealIpModule 讀取請求內容階段
NGX_HTTP_SERVER_REWRITE_PHASE (server rewrite) HttpRewriteModule / rewrite 請求地址修正階段
NGX_HTTP_FIND_CONFIG_PHASE(location selection) HttpCoreModule / location 配置尋找階段
NGX_HTTP_REWRITE_PHASE Location(location rewrite) location selection,
finalize request
HttpRewriteModule / rewrite 請求地址修正階段
NGX_HTTP_POST_REWRITE_PHASE HttpRewriteModule / rewrite 請求地址修正提交階段
NGX_HTTP_PREACCESS_PHASE degradation, NginxHttpLimitZoneModule / limit_zone,
HttpLimitReqModule / limit req, HttpRealIpModule
存取權限檢查準備階段
NGX_HTTP_ACCESS_PHASE finalize request HttpAccessModule / allow, deny, NginxHttpAuthBasicModule / auth_basic 存取權限檢查階段
NGX_HTTP_POST_ACCESS_PHASE 存取權限檢查提交階段
NGX_HTTP_TRY_FILES_PHASE location selection HttpCoreModule / try_files 配置項try_files處理階段
NGX_HTTP_CONTENT_PHASE HttpAutoindexModule / autoindex,HttpCoreModule / Core, HttpDavModule / DAV,
HttpEmptyGifModule / EmptyGif, HttpFcgiModule / FastCGI, HttpFlvStreamModul / FLV,
HttpGzipStaticModule / gzip_static, HttpIndexModule / index,
HttpMemcachedModule / memcached, EmbeddedPerlModule / perl,
HttpProxyModule / proxy, HttpProxyModule / random_index,
HttpScgiModule / scgi, HttpStubStatusModule / stub_status,
HttpUwsgiModule / uwsgi HttpLuaModule / content_by_lua,
HttpCoreModule / proxy_pass
內容產生階段
NGX_HTTP_LOG_PHASE HttpLogModuel / access_log 日誌模組處理階段
二、各個phase說明:

post read phase:

讀完要求標頭後就進入了post_read 階段,它位於uri被重寫之前,這個階段允許nginx改變要求標頭中ip地址的值,相關模組HttpRealIpModule.

server_rewrite phase:

這個階段主要進行初始化全域變數,或者server層級的重寫。如果把重寫指令放到 server 中,那麼就進入了server rewrite 階段。(重寫指令見rewrite phase)

find config phase:

這個階段使用重寫之後的uri來尋找對應的location,值得注意的是該階段可能會被執行多次,因為也可能有location層級的重寫指令。

rewrite phase:

如果把重寫指令放到 location中,那麼就進入了rewrite phase,這個階段是location層級的uri重寫階段,重寫指令也可能會被執行多次;

重寫指令有 HttpRewriteModule 的set指令,rewrite指令,HttpLuaModule的 set_by_lua指令, ngx_set_misc模組的set_unescape_uri指令,另外HttpRewriteModule的幾乎所有指令都屬於rewrite階段。

到此,思考一個問題: 既然不用module的不同重寫指令到可以在這個phase,那麼這些指令是否可以在同一個location並存,如果可以,那麼他們的執行順序是怎麼樣的?

例子1 :
思考下面例子的輸出的結果是什嗎?

 location /test {        set $a 32;        set $b 56;        set_by_lua $c "return ngx.var.a + ngx.var.b";        set $d "$a + $b = $c";        echo $d;    }

當我們訪問 http://localhost/test時,輸出結果為 32 + 56 = 88 ,應該是和我們預期一致的。

但是這並不能證明所有屬於同一個phases的不同的module的指令在一個phase中並存時一定是按照順序執行下來的。 事實上,上面提到的這些第三方模組都採用了特殊的技術,將它們自己的配置指令“注入”到了 HttpRewriteModule的指令序列中(它們都藉助了 Marcus Clyne 編寫的第三方模組 ngx_devel_kit)。換句話說,更多常規的在 Nginx 的 rewrite 階段註冊和運行指令的第三方模組就沒那麼幸運了。這些“常規模組”的指令雖然也運行在 rewrite 階段,但其配置指令和 HttpRewriteModule(以及同一階段內的其他模組)都是分開獨立執行的。在運行時,不同模組的配置指令集之間的先後順序一般是不確定的(嚴格來說,一般是由模組的載入順序決定的,但也有例外的情況)。比如 A 和 B 兩個模組都在 rewrite 階段運行指令,於是要麼是 A 模組的所有指令全部執行完再執行 B 模組的那些指令,要麼就是反過來,把 B 的指令全部執行完,再去運行 A 的指令。除非模組的文檔中有明確的交待,否則使用者一般不應編寫依賴於此種不確定順序的配置。還有不少第三方模組,ngx_array_var 以及用於加解密使用者會話(session)的 ngx_encrypted_session,也都可以和HttpRewriteModule的指令無縫混合工作。標準 HttpRewriteModule的應用是如此廣泛,所以能夠和它的配置指令混合使用的第三方模組是幸運的。不能和HttpRewriteModule混合使用的指令在實際使用的過程要引起注意,它的輸出是不確定的,這與他們在設定檔中的順序無關。

結論:範圍為同一個phase的不同modules的指令,如果modules之間做了特殊的相容,則它們按照指令在設定檔中出現的順序依次執行下來

例子2:
思考下面這個輸出什嗎?

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

訪問:curl 'http://localhost/test'
輸出:X-Species: cat
是不是和你的預期有點兒不一樣呢?

說明:第三方模組 ngx_headers_more 提供了一系列配置指令,用於操縱當前請求的要求標頭和回應標頭。其中有一條名叫 more_set_input_headers 的指令可以在 rewrite 階段改寫指定的要求標頭(或者在要求標頭不存在時自動建立)。該指令的文檔中有這麼一行標記 phase: rewrite tail,是說這條指令總是運行在 rewrite 階段的末尾。顯然,寫在 more_set_input_headers 指令之後的 set $value cat 語句卻先執行了。也就是說屬於HttpRewriteModule的set指令先執行完了,才執行ngx_header_more 的set_input_headers指令。
結論:即使運行在同一個請求處理階段,分屬不同模組的配置指令也可能會分開獨立運行(除非像 ngx_set_misc 等模組那樣針對 ngx_rewrite 模組提供特殊支援)。換句話說,在單個請求處理階段內部,一般也會以 Nginx 模組為單位進一步地劃分出內部子階段。下面的例子3同例子2:

例子3:

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

訪問: curl 'http://localhost/test'
輸出: 57

說明:HttpLuaModule的rewrite_by_lua 指令也是處在 rewrite tail phase,它也會在rewrite 階段的末尾執行。因此HttpRewriteModule的所有set執行完後,才執行它。
顯然,rewrite_by_lua 指令的行為不同於我們前面在 (二) 中介紹過的 set_by_lua 指令。
小夥伴們可能要問,既然 more_set_input_headers 和 rewrite_by_lua 指令都運行在 rewrite 階段的末尾,那麼它們之間的先後順序又是怎樣的呢?答案是:不一定。我們應當避免寫出依賴它們二者間順序的配置。

結論:範圍在同一個phase的不同modules的指令,如果沒有做特殊相容處理,則它們指令的執行順序與指令在配置中出現的順序無關,結果具有不確定性

post rewrite phase:

location層級重寫的下一階段,用來檢查上階段是否有uri重寫,並根據結果跳轉到合適的階段;

preaccess phase:

存取權限控制的前一階段,該階段在許可權控制階段之前,一般也用於存取控制,比如限制訪問頻率,連結數等;相關模組/指令 :NginxHttpLimitZoneModule / limit_zone,
HttpLimitReqModule / limit req, HttpRealIpModule

access phase:

存取權限控制階段,比如基於ip黑白名單的許可權控制,基於使用者名稱密碼的認證控制等;相關模組/指令 HttpAccessModule / allow, deny, NginxHttpAuthBasicModule / auth_basic。 HttpAccessModule提供的 allow 和 deny 配置指令可用於控制哪些 IP 位址可以訪問,哪些不可以。HttpAccessModule模組還支援所謂的“CIDR 記法”來表示一個網段,例如 169.200.179.4/24 則表示路由首碼是 169.200.179.0(或者說子網路遮罩是 255.255.255.0)的網段。

思考下下面兩個例子(例子5,例子6)
例子4:

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

本機訪問:curl http://localhost/hello ,輸出:hello world
其他機器訪問:curl http://localhost/hello ,報403錯誤

例子5:

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

本機訪問:curl http://localhost/hello ,報403錯誤
其他機器訪問:curl http://localhost/hello ,報403錯誤

例5和例6的區別在於deny all ,和allow 127.0.0.1 這兩條指令的順序不同。但例5中/hello 只允許從本機(IP 位址為保留的 127.0.0.1)訪問,而從其他 IP 位址訪問都會被拒(返回 403 錯誤頁)。而例6中被配置為任何IP訪問都會返回403錯誤。
原因說明:同屬於HttpAccessModule這個模組的多條配置指令之間是按順序執行的,直到遇到第一條滿足條件的指令就不再執行後續的 allow 和 deny 指令。如果首先匹配的指令是 allow,則會繼續執行後續其他模組的指令或者跳到後續的處理階段;而如果首先滿足的是 deny 則會立即中止當前整個請求的處理,並立即返回給用戶端 403 錯誤頁。

結論:同一個phase的同一個module內的多條指令的執行順序由這個module自己來定義。

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

post access phase:

存取權限控制的後一階段,該階段根據許可權控制階段的執行結果進行相應處理;

try files phase:

HttpCoreModule的try_files指令的處理階段,如果沒有配置try_files指令,則該階段被跳過; 該指令範圍: server ,location。
當try_files用於server階段時一般是初始化作用,用來載入一些檔案。

文法: try_files file1,file2,..,fileN-1 ... ,fallback 或者try_files file1,file2,..,fileN = code
用來順序檢查file1,file2,...fileN-1是否存在,如果最後一個字元為/表示這是一個目錄。只要找到一個file存在,則進入到content phase,輸出內容。如果前N-1個參數代表的file都不存在,此時最後一個參數發揮作用,最後一個參數用於內部跳轉,並且只有最後一個參數是用作內部跳轉,因此最後一個參數必須存在,否則將會引發一個內部錯誤。前面的file參數只是設定uri指向,不會引發內部跳轉。此外注意: try_files和rewrite不同,rewrite指令會自動儲存原請求的參數$args,而try_files最後的fallback參數如果需要帶上請求的參數,則需要明確指出,如:

try_files $uri $uri/ /index.php?q=$uri&$args

content phase:

內容產生階段,該階段產生響應,並發送到用戶端; 這個階段相關的模組和指令較多。這裡僅拿HttpLuaModule的content_by_lua和HttpEchoModule的echo指令來舉個例子再次證明上述談論到的一個結論。
例子:

 location /test {          set $a 123;          set $b 456;          echo $b;          content_by_lua '             ngx.say(ngx.var.a)           ';    }

訪問: curl http://localhost/test
輸出: 123
即只有content_by_lua裡面的ngx.say執行了,外面的echo $b指令沒有執行。echo和content_by_lua分別屬於兩個module的指令,他們的作用phase都是content phase。這兩個module不相容,
這兩條指令不是順序執行,至於執行結果是什麼,不確定,這裡是只有content_by_lua被執行了。再次證明之前的結論:範圍在同一個phase的不同modules的指令,如果沒有做特殊相容處理,則它們指令的執行順序與指令在配置中出現的順序無關,結果具有不確定性,需要盡量避免這種情況出現。
 location /test_echo {          content_by_lua '             ngx.say(ngx.var.a)           ';          set $a 123;          set $b 456;    }

log phase:

日誌記錄階段,該階段記錄訪問日誌;

三、小結:

  • 11個phases粗略介紹完了。這11個phases,不是每個請求都會經曆所有的11個phase。有可能某些phase沒有經曆,如果請求內部包含子請求,某些phase可能會出現多次。
  • 在單個請求的處理過程中,前面的phase總是在後面phase之前執行。這裡的前後值得是本文phase的介紹順序,而不是phase相關的指令在設定檔中出現的順序。
    例如,rewrite phase總是在content phase之前執行,與指令在設定檔中出現順序無關,下面的例子
    location /test {    set $a 11;    echo $a;     set $a 22;    echo $a;}

    實際執行順序為set $a 11;set $a 22;echo $a;echo $a;
    訪問:curl http://localhost/test
    輸出:
    22
    22
    理由是rewrite phase總是在content phase之前執行
  • 範圍為同一個phase的不同modules的指令,如果modules之間做了特殊的相容,則它們按照指令在設定檔中出現的順序依次執行下來
  • 範圍在同一個phase的不同modules的指令,如果沒有做特殊相容處理,則它們指令的執行順序與指令在配置中出現的順序無關,結果具有不確定性
  • 同一個phase的同一個module內的多條指令的執行順序由這個module自己來定義。

參考資料:

http://wiki.nginx.org/

http://wiki.nginx.org/Phases

http://blog.sina.com.cn/s/blog_6d579ff40100xpff.html

以上就介紹了nginx phases 介紹,包括了方面的內容,希望對PHP教程有興趣的朋友有所協助。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.