nginx實際把http請求處理流程劃分為了11個階段,這樣劃分的原因是將請求的執行邏輯細分,以模塊為單位進行處理,各個階段可以包含任意多個http模塊并以流水線的方式處理請求,這樣做的好處是使處理程序更加靈活、降低耦合度,可以讓每個HTTP模塊可以僅僅專注于完成一個獨立,簡單的功能,而一個請求的完整處理程序可以由多個HTTP模塊共同合作完成,可以極大的提高多個模塊合作的協同性,可測驗性,可擴展性,換言之,nginx在處理每一個http請求,和組態檔上的順序沒有關系,這11個http階段如下所示:
1)ngx_http_post_read_phase:
接收到完整的http頭部后處理的階段,它位于uri重寫之前,實際上很少有模塊會注冊在該階段,默認的情況下,該階段被跳過,
最先執行的 post-read 階段在 Nginx 讀取并決議完請求頭(request headers)之后就立即開始運行,例如:使用了 ngx_realip 模塊提供的 set_real_ip_from 和 real_ip_header 這兩條配置指令
2)ngx_http_server_rewrite_phase:
uri與location匹配前,修改uri的階段,用于重定向,也就是該階段執行處于server塊內,location塊外的重寫指令,在讀取請求頭的程序中nginx會根據host及埠找到對應的虛擬主機配置,
由于 server-rewrite 階段位于 post-read 階段之后,所以 server 配置塊中的 set 指令也就總是運行在 ngx_realip 模塊改寫請求的來源地址之后,
3)ngx_http_find_config_phase:
根據uri尋找匹配的location塊配置項階段,該階段使用重寫之后的uri來查找對應的location,值得注意的是該階段可能會被執行多次,因為也可能有location級別的重寫指令,
這個階段并不支持 Nginx 模塊注冊處理程式,而是由 Nginx 核心來完成當前請求與 location 配置塊之間的配對作業,換句話說,在此階段之前,請求并沒有與任何 location 配置塊相關聯,因此,對于運行在 find-config 階段之前的 post-read 和 server-rewrite 階段來說,只有 server 配置塊以及更外層作用域中的配置指令才會起作用,這就是為什么只有寫在 server 配置塊中的 ngx_rewrite 模塊的指令才會運行在 server-rewrite 階段,這也是為什么前面所有例子中的 ngx_realip 模塊的指令也都特意寫在了 server 配置塊中,以確保其注冊在 post-read 階段的處理程式能夠生效,
4)ngx_http_rewrite_phase:
上一階段找到location塊后再修改uri,location級別的uri重寫階段,該階段執行location基本的重寫指令,也可能會被執行多次,
由于 Nginx 已經在 find-config 階段完成了當前請求與 location 的配對,所以從 rewrite 階段開始,location 配置塊中的指令便可以產生作用,當 ngx_rewrite 模塊的指令用于 location 塊中時,便是運行在這個 rewrite 階段,
5)ngx_http_post_rewrite_phase:
防止重寫url后導致的死回圈,location級別重寫的后一階段,用來檢查上階段是否有uri重寫,并根據結果跳轉到合適的階段,
這個階段也像 find-config 階段那樣不接受 Nginx 模塊注冊處理程式,而是由 Nginx 核心完成 rewrite 階段所要求的“內部跳轉”操作(如果 rewrite 階段有此要求的話),例如:通過 rewrite 指令把當前請求的 URI 無條件地改寫為 /bar,同時發起一個“內部跳轉”,最終跳進了 location /bar 中,這里比較有趣的地方是“內部跳轉”的作業原理,“內部跳轉”本質上其實就是把當前的請求處理階段強行倒退到 find-config 階段,以便重新進行請求 URI 與 location 配置塊的配對,
6)ngx_http_preaccess_phase:
下一階段之前的準備,訪問權限控制的前一階段,該階段在權限控制階段之前,一般也用于訪問控制,比如限制訪問頻率,鏈接數等,
該階段在 access 階段之前執行,故名 preaccess.標準模塊 ngx_limit_req 和 ngx_limit_zone 就運行在此階段,前者可以控制請求的訪問頻度,而后者可以限制訪問的并發度,
7)ngx_http_access_phase:
讓http模塊判斷是否允許這個請求進入nginx服務器,訪問權限控制階段,比如基于ip黑白名單的權限控制,基于用戶名密碼的權限控制等,
標準模塊 ngx_access、第三方模塊 ngx_auth_request 以及第三方模塊 ngx_lua 的 access_by_lua 指令就運行在這個階段,
8)ngx_http_post_access_phase:
訪問權限控制的后一階段,該階段根據權限控制階段的執行結果進行相應處理,向用戶發送拒絕服務的錯誤碼,用來回應上一階段的拒絕,
這個階段也和 post-rewrite 階段類似,并不支持 Nginx 模塊注冊處理程式,而是由 Nginx 核心自己完成一些處理作業,post-access 階段主要用于配合 access 階段實作標準 ngx_http_core 模塊提供的配置指令 satisfy 的功能,對于多個 Nginx 模塊注冊在 access 階段的處理程式, satisfy 配置指令可以用于控制它們彼此之間的協作方式,比如模塊 A 和 B 都在 access 階段注冊了與訪問控制相關的處理程式,那就有兩種協作方式,一是模塊 A 和模塊 B 都得通過驗證才算通過,二是模塊 A 和模塊 B 只要其中任一個通過驗證就算通過,第一種協作方式稱為 all 方式(或者說“與關系”),第二種方式則被稱為 any 方式(或者說“或關系”),默認情況下,Nginx 使用的是 all 方式,
9)ngx_http_try_files_phase:
為訪問靜態檔案資源而設定,try_files指令的處理階段,如果沒有配置try_files指令,則該階段被跳過,
這個階段專門用于實作標準配置指令 try_files 的功能,并不支持 Nginx 模塊注冊處理程式,try_files 指令接受兩個以上任意數量的引數,每個引數都指定了一個 URI. 這里假設配置了 N 個引數,則 Nginx 會在 try-files 階段,依次把前 N-1 個引數映射為檔案系統上的物件(檔案或者目錄),然后檢查這些物件是否存在,一旦 Nginx 發現某個檔案系統物件存在,就會在 try-files 階段把當前請求的 URI 改寫為該物件所對應的引數 URI(但不會包含末尾的斜杠字符,也不會發生 “內部跳轉”),如果前 N-1 個引數所對應的檔案系統物件都不存在,try-files 階段就會立即發起“內部跳轉”到最后一個引數(即第 N 個引數)所指定的 URI.通過 root 配置指令所指定的“檔案根目錄”進行映射,例如,當“檔案根目錄”是 /var/www/ 的時候,請求 URI /foo/bar 會被映射為檔案 /var/www/foo/bar,而請求 URI /foo/baz/ 則會被映射為目錄 /var/www/foo/baz/. 注意這里是如何通過 URI 末尾的斜杠字符是否存在來區分“目錄”和“檔案”的,
10)ngx_http_content_phase:
處理http請求內容的階段,大部分http模塊介入這個階段,內容生成階段,該階段產生回應,并發送到客戶端,
Nginx 的 content 階段是所有請求處理階段中最為重要的一個,因為運行在這個階段的配置指令一般都肩負著生成“內容”(content)并輸出 HTTP 回應的使命,正因為其重要性,這個階段的配置指令也例外豐富,如echo、 echo_exec 指令, proxy_pass 指令, echo_location 指令,content_by_lua,
11)ngx_http_log_phase:
log階段處理,比如記錄訪問量/統計平均回應時間,log_by_lua
處理完請求后的日志記錄階段,該階段記錄訪問日志,
以上11個階段中,http無法介入的階段有4個:
3)ngx_http_find_config_phase
5)ngx_http_post_rewrite_phase
8)ngx_http_post_access_phase
9)ngx_http_try_files_phase
剩余的7個階段,http模塊均能介入,每個階段可介入模塊的個數也是沒有限制的,多個http模塊可同時介入同一階段并作用于同一請求,
參考博客:https://www.cnblogs.com/zhenyuyaodidiao/p/9288430.html
https://www.cnblogs.com/vinsent/p/12259287.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/86600.html
標籤:Linux
下一篇:應用系統分布式構建運維
