參考資料<深入理解Nginx>(陶輝)
處理HTTP請求
接着上一次的內容,本次將說明HTTP框架是如何召集負責具體功能的各HTTP模塊合作處理請求的。
在http://www.cnblogs.com/runnyu/p/4918135.html的最后是通過ngx_http_process_request方法開始處理請求的,該方法流程如下圖
2.設置讀、寫事件的回調方法為ngx_http_request_handler方法,請求的后續處理都是通過ngx_http_request_handler方法進行的。
6.設置ngx_http_request_t結構體的write_event_handler成員為ngx_http_core_run_phases方法。該方法可能會被多次調度來完成HTTP請求的處理。
7.調用ngx_http_core_run_phases回調方法,該方法執行流程如下
ngx_http_request_t結構體中的phase_handler成員(處理流程的核心)將決定執行到哪一階段,關於該成員跟其相關的數據結構可以查看http://www.cnblogs.com/runnyu/p/4910952.html。
該回調方法的源碼如下
void ngx_http_core_run_phases(ngx_http_request_t *r) { ngx_int_t rc; ngx_http_phase_handler_t *ph; cmcf=ngx_http_get_module_man_conf(r,ngx_http_core_module); ph=cmcf->phase_engine.handlers; while(ph[phase_handler].checker){ rc=ph[r->phase_handler].checker(r,&ph[r->phase_hanlder]); if(rc==NGX_OK){ return; } } }
只有當相應的checker方法返回NGX_OK時才將控制權交還給Nginx的事件模塊,否則將繼續執行(checker方法中會修改phase_handler成員以向下執行)。
當這個請求上對應的事件再次觸發時,HTTP框架將回調ngx_http_request_handler方法開始處理請求(上面已經設置了該方法為其讀、寫事件的回調方法)。
下圖是ngx_http_request_handler方法的流程
2.如果當前事件可寫,將調用ngx_http_reqeust_t結構體中的write_event_handler方法。該方法在上面已經設置為ngx_http_core_run_phases,可見該方法會被多次調用。
Checker方法
checker方法是HTTP框架定義的,每一個HTTP處理階段對應着相應着一個checker方法(有的階段的checker方法一樣),handler方法只有在checker方法中調用。
checker方法的主要任務在於,根據phase_handler執行某個HTTP模塊實現的回調方法,並根據方法的返回值決定:
1.當前階段是否已經結束
2.下次要執行的回調方法是哪一個
3.是立刻執行下一個回調方法還是先把控制權交還給epoll
下面介紹HTTP框架中其中兩個checker方法的介紹
ngx_http_core_generic_phase
在前面的http://www.cnblogs.com/runnyu/p/4910952.html下面有該方法的介紹,下面只給出該方法的流程圖
可見,checker方法主要是根據handler方法的返回值來改變phase_handler的值以用來控制handler方法的執行順序的。
ngx_http_core_content_phase
ngx_http_core_content_phase是NGX_HTTP_CONTENT_PHASE階段的checker方法。是我們開發HTTP模塊時最常用的一個階段。
其余10個階段中各HTTP模塊的handler方法都是放在全局ngx_http_core_main_conf_t結構體中,而該階段的handler方法則可以放在ngx_http_core_conf_t結構體中,這就是按需掛載的基礎
typedef struct ngx_http_core_loc_conf_s ngx_http_core_loc_conf_t
struct ngx_http_core_loc_conf_s { ... ngx_http_handler_pt handler; ... }
在我們最初的開發的HTTP模塊中:http://www.cnblogs.com/runnyu/p/4871866.html
當檢測到mytest配置項后,調用ngx_http_mytest方法將上面ngx_http_core_loc_conf_t的handler成員設置為自己的handler函數,實現了按需掛載。
事實上,在NGX_HTTP_FIND_CONFIG_PHASE階段就會把ngx_http_request_t結構體的content_handler成員設置為匹配請求URI的location下的ngx_http_core_loc_conf_t結構體的handler成員。
下面是該checker方法的流程圖,可以看出是如何實現按需掛載的
處理HTTP包體
在接收完HTTP頭部后,就開始調用各HTTP模塊處理請求了,然后由HTTP模塊決定如何處理包體(handler函數)。
1.接收包體
ngx_int_t ngx_http_read_client_request_body(ngx_http_request *r,ngx_http_client_body_handler_pt post_handler); typedef void (*ngx_http_client_body_handler_pt) (ngx_http_request_t *r);
接收到的包體保存在ngx_http_reqeust_body_t中,一般調用該函數的handler函數會接着返回NGX_DONE。
在完成接收動作之后,會調用post_handler函數繼續處理請求。
2.放棄接收包體(Nginx必須接收包體,但不做處理)
ngx_int ngx_http_discard_reqeust_body(ngx_http_request_t *r);
調用該函數的handler函數繼續處理請求,Nginx會異步地接收跟丟棄包體。
發送HTTP響應
顯然,發送HTTP響應也是在handler函數中調用的。
1.發送響應頭
ngx_int_t ngx_http_send_header(ngx_http_request_t *r);
該方法會異步地根據ngx_http_reqeust_t中的header_out成員將HTTP頭部發送給客戶端(經過各個過濾模塊)。
2.發送響應體
ngx_int_t ngx_http_output_filter(ngx_http_request_t *r,ngx_chain_t *in);
該方法會異步地根據參數in將HTTP響應體發送給客戶端(經過各個過濾模塊)。