nginx HTTP處理流程
監聽套接字ngx_listenting_t->fd由獲取accept_mutex的worker進程加入epoll監控,其handler爲ngx_event_accept;
注:每一個fd賦予一個ngx_connection_t,且c->read->handler = ngx_event_accept(詳見ngx_event_process_init);
當客戶端發起新鏈接時,epoll_wait返回,將其加入accepted隊列,而後調用ngx_event_accept處理;
接受完客戶端鏈接後,當即調用ngx_listening_t->handler,即ngx_http_init_connection;nginx
ngx_http_init_connection
- 將當前鏈接的讀事件revent->handler設置爲ngx_http_init_request;
- 將當前鏈接的讀事件revent加入定時器,超時時間爲client_header_timeout;
- 將當前鏈接的讀事件revent加入epoll監控;
- (注):當鏈接第一次出現可讀事件時,纔會調用ngx_http_init_request
ngx_http_init_request
- 檢查是否超時client_header_timeout; 超時關閉連接。
- 建立ngx_http_request_t,找到監聽地址對應的sever,並設置這個請求對應的http配置項,
- (從新設置讀事件的回調方法)將revent->handler重置爲ngx_http_process_request_line;
- 建立讀緩衝區client_header_buffer_size && ngx_http_request_t內存池(建立緩衝區內存池,初始化ngx_http_request_t結構體中的容器,建立指針數組以存放全部HTTP模板對該請求可能建立的上下文結構體,更新ngx_http_request_t 結構體的請求開始時間)
- 爲ngx_http_request_t->ctx分配ngx_http_max_module個成員的指針數組(注1);
- 調用ngx_http_process_request_line;
注1: http請求上下文數組
Nginx採用全異步機制,一個http請求可能要屢次調度http模塊才能完成,須要上下文結構體保存處理過程的中間狀態;異步
一個http請求對應每一個http模塊都有一個獨立的上下文結構體,由ngx_http_request_t -> ** ctx保存;post
每一個模塊上下文結構體各異,一般在http請求第一次調用handler時分配;
Nginx提供兩個宏用於獲取和設置上下文指針
#define ngx_http_get_module_ctx(r,module) (r)->ctx[module.ctx_index]
#define ngx_http_set_ctx(r, c, module) r->ctx[module.ctx_index] = c;
ngx_http_process_request_line
- 接收請求行,格式爲: 請求方法 uri http版本,(可調用屢次)
- 執行完畢後將revent->handler重置爲ngx_http_process_request_headers
- 解析請求頭;
- 調用ngx_http_process_request處理http請求;
ngx_http_process_request
- 把讀事件從定時器移除,無需再接受http請求頭;
- 將當前鏈接讀事件c->read->handler設置爲ngx_http_request_handler;(從新設置讀、寫事件的回調方法)
- 檢查ngx_http_request_t->internal,爲1表示須要跳轉,將phase_handler改成server_rewrite_index,即調用NGX_HTTP_SERVER_REWRITE_PHASE階段的handler;
- 設置ngx_http_request_t->write_event_handler = ngx_http_core_run_phases;
- 調用ngx_http_core_run_phases;
- 執行post子請求;
ngx_http_read_client_request_body
ngx_http_output_filter
ngx_http_writer
接受請求
- ngx_http_close_connection
- ngx_http_free_request
- ngx_http_close_request
- ngx_http_finalize_connecion
- ngx_http_terminate_request
- ngx_http_finalize_request
問1:nginx擁有衆多http模塊,如何將其整合並確保http請求會用到相應模塊?code
- nginx將http請求劃分11個階段,每一階段可包含多個http模塊,每一個模塊handler運行結果決定下一個模塊;
- 每一個http階段由ngx_http_phase_handler_s描述,包含3個成員:checker,handler以及 next;
- Nginx不容許直接調用http模塊的handler,而是經過提供的checker封裝調用,共有7個http請求階段實現了checker(4個),也就是說只有這7個階段容許第3方模塊註冊;
* Nginx初始化時,調用每一個http模塊的ngx_http_module_t->postconfiguration將自身的handler加入cmcf->phases(二維數組);
- 而後經過ngx_http_init_phase_handlers()將cmcf->phases重組爲一維數組cmcf->phase_engine.handlers,此時全部的ngx_http_phase_handler_s都位於其中;
- 一個http請求通過解析請求行和請求頭後,最終調用ngx_http_core_run_phases,其以http請求的phase_handler爲下標,嘗試遍歷cmcf->phase_engine.handlers (可能由於處理結果提早返回)
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;
while (ph[r->phase_handler].checker) {
rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);
if (rc == NGX_OK) {
return;
}
}
}
以上是接受客戶端鏈接,並根據http請求行和請求頭執行相應http模塊,http請求可能還有包體,由http模塊負責處理;
通常有兩種方法: 1 接收包體並存入內存或文件; 2 接收包體後直接丟棄;server