Nginx-HTTP框架的初始化

原創:https://blog.csdn.net/ndzjx/article/details/89222809

 

HTTP框架大致由1個核心模塊(ngx_http_module)、兩個HTTP模塊(ngx_http_core_module、ngx_http_upstream_module)組成,它將負責調度其他HTTP模塊來一起處理用戶請求。首要任務是通過ngx_http_module_t接口中的方法來管理所有HTTP模塊的配置項。

Server虛擬主機會以散列表的數據結構組織起來,高效查詢。

Location表達式會以一個靜態的二叉查找樹組織起來。不使用紅黑樹,是因爲location是從nginx.conf中讀取到的,是靜態不變的,不存在運行過程中添加刪除的場景,而且紅黑樹的查詢效率也沒有重新構造的靜態的完全平衡二叉樹高。(ngx_http_init_locations/nginx_http_init_static_location_trees)

typedef struct {
    ngx_int_t   (*preconfiguration)(ngx_conf_t *cf);
    ngx_int_t   (*postconfiguration)(ngx_conf_t *cf);

    void       *(*create_main_conf)(ngx_conf_t *cf);
    char       *(*init_main_conf)(ngx_conf_t *cf, void *conf);

    void       *(*create_srv_conf)(ngx_conf_t *cf);
    char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);

    void       *(*create_loc_conf)(ngx_conf_t *cf);
    char       *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
} ngx_http_module_t;

1:處理http{}塊內的main級別配置項時,對每個HTTP模塊,都會調用create_main_conf、create_srv_conf、create_loc_conf建立3個結構體,這是爲了把同時出現在http{},server{},location{}內的相同配置項進行合併而做的準備。

2:處理server{}內的srv級別配置項時,需要調用每個HTTP模塊的create_srv_conf、create_loc_conf

3:處理location{}內的loc級別配置項時,調用HTTP每個模塊的create_loc_conf方法建立結構體

 

解析http{}

ngx_http_core_module模塊完成了HTTP框架的大部分功能,而它又是一個HTTP模塊,使用到了比較關心的3個結構體(ngx_http_core_main_conf_t、ngx_http_core_srv_conf_t、ngx_http_core_loc_conf_t)

typedef struct {
    void        **main_conf;
    void        **srv_conf;
    void        **loc_conf;
} ngx_http_conf_ctx_t;

通過ngx_cycle_t找到main級別的配置結構體:

#define ngx_http_cycle_get_module_main_conf(cycle, module)                    \
    (cycle->conf_ctx[ngx_http_module.index] ?                                 \
        ((ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index])      \
            ->main_conf[module.ctx_index]:                                    \
        NULL)

 

 

解析server塊

首先會像解析http塊一樣,建立屬於這個server塊的ngx_http_conf_ctx_t結構體。

如果server{}內沒有解析到listen配置項,默認監聽端口80,當進程沒有權限監聽1024以下的端口時,則會監聽8000端口。

ngx_http_core_module模塊的ngx_http_core_main_conf_t結構中有一個servers動態數組。

 

 

 

解析location配置塊

仍然會像解析http塊一樣,先建立ngx_http_conf_ctx_t結構體。

 

同一個server下的location, ngx_http_core_loc_conf_t結構體構成一個雙向鏈表。(非侵入式鏈表)

 

location下還可以嵌套location,同樣,會生成鏈表。

 

 

 

監聽端口的管理:

監聽端口屬於server虛擬主機,由listen配置項決定,與server{}塊對應的ngx_http_core_srv_conf_t結構體密切相關。每一個TCP端口,都將使用一個獨立的ngx_http_conf_port_t結構體表示。

ngx_http_conf_port_t的addrs動態數組可能不太容易理解。如:對同一個端口8000,我們可以同時監聽127.0.0.1:8000、173.39.160.51:8000這兩個地址,當一臺物理機器具備多個IP地址時這是很有用的

監聽端口與server虛擬主機的關係:

 

 

 

HTTP請求的11個階段:

    1)post_read : 接受到完整的http頭部後處理的階段

    2)server_rewrite:URI與location匹配前,可以修改URI(重定向)

    3)find_config:根據URI尋找匹配的location表達式

    4)rewrite:location匹配後可以再修改URI

    5)post_rewrite:rewrite修改URI後,防止錯誤的nginx.conf配置導致死循環,如果一個請求超過10次重定向,就認爲i進入了rewrite死循環。

    6)pre_access:處理訪問權限前,可以介入的階段

    7)access:是否允許請求訪問Nginx服務器

    8)post_access:如果不允許訪問,向用戶發送拒絕服務的錯誤響應。

    9)pre_content:包含try_files指令,訪問靜態文件資源

    10)content:處理HTTP請求內容的階段

    11)log:處理完請求後記錄日誌的階段

其中:find_config、post_rewrite、post_access、pre_content 4個階段不允許HTTP模塊加入自己的ngx_http_handler_pt方法處理用戶請求,它們僅由HTTP框架實現。

struct ngx_http_phase_handler_s {
    ngx_http_phase_handler_pt  checker; // 由ngx_http_core_module實現
    ngx_http_handler_pt        handler; 
    ngx_uint_t                 next; // 使得處理階段不必按順序依次執行
};

ngx_http_phase_engine_t結構體就是所有ngx_http_phase_handler_t組成的數組。此結構體在全局的ngx_http_core_main_conf_t結構體中。ngx_http_core_main_conf_t中還有一個phases數組,保存11個階段每個階段要執行的handlers

typedef struct {
    ngx_http_phase_handler_t  *handlers;
    ngx_uint_t                 server_rewrite_index; // 跳轉到server_rewrite階段處理
    ngx_uint_t                 location_rewrite_index;  // 跳轉的rewrite
} ngx_http_phase_engine_t;

 

向指定階段添加handler的方法大致如下:

在ngx_http_module_t接口的postconfiguration方法中將自定義的方法添加到handler動態數組中。

h = ngx_array_push(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers);

if (h == NULL) {

return NGX_ERROR;

}

*h = ngx_http_realip_handler;

 

其中,content階段還有一個獨有的方法可以添加handler:

把希望處理請求的ngx_http_handler_pt方法設置到location相關的ngx_http_core_loc_conf_t結構體的handler指針中。

好處是:

處理方法不再應用於所有HTTP請求,僅URI匹配時纔會被調用。

注意:

這種情況下,每個content階段只能有一個ngx_http_handler_pt處理方法。這種方式優先於使用postconfiguration設置的方法,postconfiguration設置的方法會失效。

 

 

ngx_http_block方法,包括了HTTP框架的完整初始化流程:

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章