1. 程式人生 > >NGINX中HTTP請求的11個處理階段

NGINX中HTTP請求的11個處理階段

Nginx的模組化設計使得每一個HTTP模組可以僅專注於完成一個獨立的、簡單的功能,而一個請求的完整處理過程可以由無數個HTTP模組共同合作完成。這種設計有非常好的簡單性、可測試性、可擴充套件性,然而,當多個http模組流水式地處理同一個請求時,單一的處理順序是無法滿足靈活性需求的,每一個正在處理的HTTP模組很難靈活、有效地指定下一個HTTP處理模組是哪一個。

因此,HTTP框架依據常見的處理流程將處理階段劃分為11個階段,其中每個處理階段都可以由任意多個HTTP模組流水式地處理請求。

typedef enum {
    //在接收到完整的HTTP頭部後處理的HTTP階段
    NGX_HTTP_POST_READ_PHASE = 0,
 
    //在請求的URI與location表示式匹配前,修改請求的URI(重定向),是一個獨立的HTTP階段
    NGX_HTTP_SERVER_REWRITE_PHASE,
 
    //根據請求的URI尋找匹配的location表示式,這個階段只能由
    NGX_HTTP_FIND_CONFIG_PHASE,
         
    //在NGX_HTTP_FIND_CONFIG_PHASE階段尋找到匹配的location之後再修改請求的URI
    NGX_HTTP_REWRITE_PHASE,
         
    //這一階段是用於在rewrite重寫URL後,防止錯誤的nginx.conf配置導致死迴圈(遞迴地修改URI)
    NGX_HTTP_POST_REWRITE_PHASE,
 
    //表示在處理NGX_HTTP_ACCESS_PHASE階段覺得請求的訪問許可權前,HTTP模組可以介入的處理階段
    NGX_HTTP_PREACCESS_PHASE,
 
    //這個階段用於讓HTTP模組判斷是否允許這個請求訪問nginx伺服器
    NGX_HTTP_ACCESS_PHASE,
         
    //在NGX_HTTP_ACCESS_PHASE階段中,當HTTP模組的handler處理函式返回不允許訪問的錯誤碼時(NGX_HTTP_FORBIDDEN或者NGX_HTTP_UNAUHORIZED),這裡將負責向用戶傳送拒絕服務的錯誤響應。
    NGX_HTTP_POST_ACCESS_PHASE,
 
    //此階段專門為try_files配置項設立,當HTTP請求訪問靜態檔案資源時,try_files配置項可以使這個配置項順序地訪問多個靜態檔案資源
    NGX_HTTP_TRY_FILES_PHASE,
         
    //用於處理HTTP請求內容的階段,這是大部分HTTP模組最願意介入的階段
    NGX_HTTP_CONTENT_PHASE,
 
    //處理完請求後記錄日誌的階段,ngx_http_log_module模組就在這個階段中加入了一個handler處理方法,使得每個HTTP請求處理完畢後會記錄access_log訪問日誌
    NGX_HTTP_LOG_PHASE
} ngx_http_phases;

這11個階段有些是必備的,有些是可選的,也可以有多個HTTP模組同時介入同一階段

HTTP階段的定義,包括checker檢查方法和handler處理方法,如下所示:

typedef structngx_http_phase_handler_s ngx_http_phase_handler_t;
 
/*一個HTTP處理階段中的checker檢查方法,僅可以由HTTP框架實現,以此控制HTTP請求的處理流程*/
typedef ngx_int_t(*ngx_http_phase_handler_pt)(ngx_http_request_t *r, ngx_http_phase_handler_t*ph);

/*由HTTP模組實現的handler處理方法*/
typedef ngx_int_t(*ngx_http_handler_pt)(ngx_http_request_t *r);

struct ngx_http_phase_handler_s {
	/*在處理到某一個HTTP階段時,HTTP框架將會在checker方法已實現的前提下首先呼叫checker方法來處理請求,
	而不會直接呼叫任何階段中的hanlder方法,只有在checker方法中才會去呼叫handler方法,因此,事實上所有
	的checker方法都是由框架中的ngx_http_core_module模組實現的,且普通模組無法重定義checker方法*/
	ngx_http_phase_handler_pt  checker;
	   
	/*除ngx_http_core_module模組以外的HTTP模組,只能通過定義handler方法才能介入某一個HTTP處理階段以處理請求*/
	ngx_http_handler_pt        handler;
	   
	/*將要處理的下一個HTTP處理階段的序號
	next的設計使得處理階段不必按順序依次執行,既可以向後跳躍數個階段繼續執行,也可以跳躍到之前的某個階段重新
	執行,通常,next表示下一個處理階段中的第1個ngx_http_phase_handler_t處理方法*/
	ngx_uint_t                 next;
};

一個http{}塊解析完畢後,將會根據nginx.conf中的配置產生由ngx_http_phase_handler_t組成的陣列,在處理HTTP請求時,一般情況下這些階段是順序向後執行的,但ngx_http_phase_handler_t中的next成員使得它們也可以非順序地執行,ngx_http_phase_engine_t結構體就是所有ngx_http_phase_handler_t組成的陣列,如下所示:

typedef struct {
	/*handlers是由ngx_http_phase_handler_t構成的陣列首地址,它表示一個請求可能經歷的所有ngx_http_handler_pt處理方法*/
	ngx_http_phase_handler_t  *handlers;
	   
	/*表示NGX_HTTP_SERVER_REWRITE_PHASE階段第1個ngx_http_phase_handler_t處理方法在handlers陣列中的序號,用於在執行
	HTTP請求的任何階段中快速跳轉到HTTP_SERVER_REWRITE_PHASE階段處理請求*/
	ngx_uint_t                 server_rewrite_index;
	   
	/*表示NGX_HTTP_PREACCESS_PHASE階段第1個ngx_http_phase_handler_t處理方法在handlers陣列中的序號,用於在執行
	HTTP請求的任何階段中快速跳轉到NGX_HTTP_PREACCESS_PHASE階段處理請求*/
	ngx_uint_t                 location_rewrite_index;
} ngx_http_phase_engine_t;

可以看到,ngx_http_phase_engine_t中儲存了在當前nginx.conf配置下,一個使用者請求可能經歷的所有ngx_http_handler_pt處理方法,這是所有HTTP模組可以合作處理使用者請求的關鍵,這個ngx_http_phase_engine_t結構體儲存在全域性的ngx_http_core_main_conf_t結構體中,如下:

typedef struct {
	ngx_array_t                servers;         /* ngx_http_core_srv_conf_t */
	/*由下面各階段處理方法構成的phases陣列構建的階段引擎才是流水式處理HTTP請求的實際資料結構*/
	ngx_http_phase_engine_t    phase_engine;
	ngx_hash_t                 headers_in_hash;
	ngx_hash_t                 variables_hash;
	ngx_array_t                variables;       /* ngx_http_variable_t */
	ngx_uint_t                 ncaptures;
	ngx_uint_t                 server_names_hash_max_size;
	ngx_uint_t                 server_names_hash_bucket_size;
	ngx_uint_t                 variables_hash_max_size;
	ngx_uint_t                 variables_hash_bucket_size;
	ngx_hash_keys_arrays_t    *variables_keys;
	ngx_array_t               *ports;
	ngx_uint_t                 try_files;       /* unsigned  try_files:1 */
	/*用於在HTTP框架初始化時幫助各個HTTP模組在任意階段中新增HTTP處理方法,它是一個有11個成員的ngx_http_phase_t陣列,
	其中每一個ngx_http_phase_t結構體對應一個HTTP階段,在HTTP框架初始化完畢後,執行過程中的phases陣列是無用的*/
	ngx_http_phase_t           phases[NGX_HTTP_LOG_PHASE + 1];
} ngx_http_core_main_conf_t;

在ngx_http_phase_t中關於HTTP階段有兩個成員:phase_engine和phases,其中phase_engine控制執行過程中的一個HTTP請求所要經過的HTTP處理階段,它將配合ngx_http_request_t結構體中的phase_handler成員使用(phase_handler制定了當前請求應當執行哪一個HTTP階段);而phases陣列更像一個臨時變數,它實際上僅會在Nginx啟動過程中用到,它的唯一使命是按照11個階段的概率初始化phase_engine中的handlers陣列

typedef struct {
	/*handlers動態陣列儲存著每一個HTTP模組初始化時新增到當前階段的處理方法*/
	ngx_array_t                handlers;
} ngx_http_phase_t;
在HTTP框架的初始化過程中,任何HTTP模組都可以在ngx_http_module_t介面的postconfiguration方法中將自定義的方法新增到handler動態陣列中,這樣,這個方法就會最終新增到phase_engine動態陣列中。

參考:《深入理解Nginx模組開發與架構設計》 陶輝  機械工業出版社