phase_handler的處理流程
1.nginx把請求的處理過程分為11個階段
typedef enum {
NGX_HTTP_POST_READ_PHASE = 0, /* 讀取請求 */
NGX_HTTP_SERVER_REWRITE_PHASE, /* server級別的rewrite */ NGX_HTTP_FIND_CONFIG_PHASE, /* 根據uri查詢location */ NGX_HTTP_REWRITE_PHASE, /* localtion級別的rewrite */ NGX_HTTP_POST_REWRITE_PHASE, /* server、location級別的rewrite都是在這個phase進行收尾工作的 */ NGX_HTTP_PREACCESS_PHASE, /* 粗粒度的access */ NGX_HTTP_ACCESS_PHASE, /* 細粒度的access,比如許可權驗證、存取控制 */ NGX_HTTP_POST_ACCESS_PHASE, /* 根據上述兩個phase得到access code進行操作 */ NGX_HTTP_TRY_FILES_PHASE, /* 實現try_files指令 */ NGX_HTTP_CONTENT_PHASE, /* 生成http響應 */ NGX_HTTP_LOG_PHASE /* log模組 */
} ngx_http_phases;
這些階段都是按照順序往下執行,只有在rewrite以後才會跳轉到ngx_http_find_config_phase階段進行處理
11箇中只有7個可以加入使用者自己定製的handler,
2.三個主要的資料結構
1》typedef struct {
/**
* 所有phase handler的陣列。
*/
ngx_http_phase_handler_t *handlers;
/** * server rewrite階段的handler在ngx_http_core_main_conf_t->phase_engine.handlers陣列中的下標 */ ngx_uint_t server_rewrite_index; /** * rewrite階段的handler在ngx_http_core_main_conf_t->phase_engine.handlers陣列中的下標 */ ngx_uint_t location_rewrite_index;
} ngx_http_phase_engine_t;
2》struct ngx_http_phase_handler_s {
/* 執行校驗,並呼叫handler函式,同一個phase的handler的checker相同 */
ngx_http_phase_handler_pt checker;
/* handler函式指標 */
ngx_http_handler_pt handler;
/*
* 指向下一個phase的第一個handler在ngx_http_core_main_conf_t->phase_engine.handlers陣列中的下標
*
*/
ngx_uint_t next;
};
3.初始化:
1》 先呼叫ngx_http_init_phases為ngx_http_core_main_conf_t->phases分配空間
2》而後呼叫http module的postconfiguration回撥函式,每個http模組都會有該函式,在該函式中實現phase_handler的註冊,模組根據自己的特點把自己的handler新增到11個階段對應得陣列中
3》而後再呼叫ngx_http_init_phase_handlers初始化ngx_http_core_main_conf_t->phase_engine
ngx_http_init_phase_handlers的實現:
在該函式的實現中,首先是根據ngx_http_core_main_conf_t結構體中的phases陣列以及對應得rewrite階段確定Phases_handler中handlers陣列的大小,這裡會給他分配儲存空間,然後依次遍歷每一個階段,初始化每一個階段的checker和next欄位
呼叫完成以後phase handler的初始化就完成了。handler的呼叫是在checker中進行的
4.phase handler的呼叫:
在ngx_http_core_run_phases是用來跑一邊phase handler的
void
ngx_http_core_run_phases(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_http_phase_handler_t *ph;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
ph = cmcf->phase_engine.handlers;
/* 遍歷phase上註冊的所有handler,這裡是以r->phase_handler為索引組成的連結串列 */
while (ph[r->phase_handler].checker) {
rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);
/* 如果一個checker返回ok,則後面的handler不會被呼叫 */
if (rc == NGX_OK) {
return;
}
}
}
//注意他是在checker的內部改變phase_handler的值得
4.phase handler的checker方法:
handler的返回值決定了checker的返回值,而checker的返回值決定了是否執行下一個handler
返回ngx_ok:本phase處理完,可以繼續執行下一個phase的handler,checker返回ngx_again
返回ngx_declined,handler由於某種原因執行失敗,但不影響本phase其他handler的執行,所以繼續執行本階段的其他handler,返回ngx_again
返回ngx_again或者ngx_done,表示請求處理完畢,checker返回ngx_ok
返回ngx_error,終結請求,釋放資源
5.主要的一個checker方法ngx_http_core_content_phase
這個階段有一個比較特殊的content_handler,如果location階段設定了handler,那麼他就是content_handler,如果有content_handler的話,那麼就只執行該一個Handler,而不去執行其他的
如果沒有content_handler的話,那麼就去執行對應得handler,且只有該handler返回ngx_declined的時候才去往下執行,否則就返回ngx_ok.