nginx HTTP處理流程

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_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

  • 接收請求body

ngx_http_send_header

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

相關文章
相關標籤/搜索