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;

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保存;

每個模塊上下文結構體各異,通常在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請求會用到相應模塊?

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM