nginx處理http請求流程

dbasdk發表於2015-01-19

監聽套接字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;

 

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,

  將revent->handler重置為ngx_http_process_request_line;

  建立讀緩衝區client_header_buffer_size   &&  ngx_http_request_t記憶體池

 為ngx_http_request_t->ctx分配ngx_http_max_module個成員的指標陣列(注1);

  呼叫ngx_http_process_request_line;

 

ngx_http_process_request_line

   接收請求行,格式為: 請求方法  uri  http版本;

   可呼叫多次;

   執行完畢後將revent->handler重置為ngx_http_process_request_headers;

 

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子請求;

 

 

問1:nginx擁有眾多http模組,如何將其整合並確保http請求會用到相應模組?

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 接收包體後直接丟棄;

 

 

注1: http請求上下文

Nginx採用全非同步機制,一個http請求可能要多次排程http模組才能完成,需要上下文結構體儲存處理過程的中間狀態;

一個http請求對應每個http模組都有一個獨立的上下文結構體,由ngx_http_request_t -> ** ctx儲存;

每個模組上下文結構體各異,通常在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;


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29734436/viewspace-1406853/,如需轉載,請註明出處,否則將追究法律責任。

相關文章