nginx實際把http請求處理流程劃分爲了11個階段,這樣劃分的緣由是將請求的執行邏輯細分,以模塊爲單位進行處理,各個階段能夠包含任意多個http模塊並以流水線的方式處理請求。這樣作的好處是使處理過程更加靈活、下降耦合度。可讓每一個HTTP模塊能夠僅僅專一於完成一個獨立,簡單的功能。而一個請求的完整處理過程能夠由多個HTTP模塊共同合做完成。能夠極大的提升多個模塊合做的協同性,可測試性,可擴展性。換言之,nginx在處理每個http請求,和配置文件上的順序沒有關係。這11個http階段以下所示:html
1)ngx_http_post_read_phase:nginx
接收到完整的http頭部後處理的階段,它位於uri重寫以前,實際上不多有模塊會註冊在該階段,默認的狀況下,該階段被跳過。服務器
最早執行的 post-read 階段在 Nginx 讀取並解析完請求頭(request headers)以後就當即開始運行。例如:使用了 ngx_realip 模塊提供的 set_real_ip_from 和 real_ip_header 這兩條配置指令併發
2)ngx_http_server_rewrite_phase:post
uri與location匹配前,修改uri的階段,用於重定向,也就是該階段執行處於server塊內,location塊外的重寫指令,在讀取請求頭的過程當中nginx會根據host及端口找到對應的虛擬主機配置。測試
因爲 server-rewrite 階段位於 post-read 階段以後,因此 server 配置塊中的 set 指令也就老是運行在 ngx_realip 模塊改寫請求的來源地址以後。lua
3)ngx_http_find_config_phase:url
根據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 階段的處理程序可以生效。server
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模塊可同時介入同一階段並做用於同一請求。