參考資料<深入理解Nginx>
一個nginx.conf的例子
http { mytest_num 1; server { server_name A; listen 80; mytest_num 2; location /L1 { mytest_num 3; } location /L2 { mytest_num 4; } } server { server_name B; listen 80; location /R1 { mytest_num 5; } location /R2 { mytest_num 6; } } }
核心結構體ngx_http_conf_ctx_t
typedef struct { //指向一個指針數組,數組中的每個成員都是由所有HTTP模塊的create_main_conf方法創建的存放全局配置項的結構體 void **main_conf; //指向一個指針數組,數組中的每個成員都是由所有HTTP模塊的create_srv_conf方法創建的存放與server相關的結構體 void **srv_conf; //指向一個指針數組,數組中的每個成員都是由所有HTTP模塊的create_loc_conf方法創建的存放與location相關的結構體 void **loc_conf; } ngx_http_conf_ctx_t;
管理main級別下的配置項
在處理http{}塊內的main級別配置項時,對每個HTTP模塊,都會調用create_main_conf、create_srv_conf、create_loc_conf方法建立3個結構體。
它們將以下面所示的數據結構保存起來
管理server級別下的配置項
在解析main級別配置項時,如果發現了server{}配置項,就會回調ngx_http_core_server方法解析srv級別的配置項。
在處理server{}塊內的srv級別配置項時,對於每個HTTP模塊,都會調用create_srv_conf、create_loc_conf方法建立兩個結構體
(其main_conf指針指向所屬的http塊下ngx_http_conf_ctx_t結構體的main_conf指針數組)。
那么HTTP框架是如何管理srv級別的配置項的呢?事實上,在解析main級別的配置項時ngx_http_core_module模塊的create_main_conf方法創建了一個很重要的結構體ngx_http_core_main_conf_t:
typedef struct { //存儲指針的動態數組,每個指針指向ngx_http_core_srv_conf_t結構體的地址,用於管理srv級別的配置項 ngx_array_t servers; ... } ngx_http_core_main_conf_t;
而在解析srv級別配置項時,ngx_http_core_module模塊會調用create_srv_conf方法創建一個ngx_http_core_srv_conf_t結構體:
typedef struct { //指向當前server塊所屬的ngx_http_conf_ctx_t結構體 ngx_http_conf_ctx_t *ctx; //當前server塊的虛擬主機名 ngx_str_t server_name; ... } ngx_http_core_srv_conf_t;
它們的關系如下圖所示
管理location級別下的配置項
在解析srv級別配置項時,如果發現了location{}配置項,就會回調ngx_http_core_location方法來解析loc級別的配置項
在處理location{}塊內的loc級別的配置項時,對於每個HTTP模塊,都會調用create_loc_conf方法來建立一個結構體
(其main_conf和srv_conf指針都指向所屬的server塊下ngx_http_conf_ctx_t結構體的main_conf和srv_conf指針數組)。
那么location級別的配置項時如何管理起來的呢?首先在解析loc級別的配置項時,ngx_http_core_module模塊會在create_loc_conf方法中生成ngx_http_core_loc_conf_t結構體:
struct ngx_http_core_loc_conf_s { //location的名稱,即nginx.conf中location后的表達式 ngx_str_t name; //指向所屬location塊內ngx_http_conf_ctx_t結構體中的loc_conf指針數組,它保存着當前location塊內所有HTTP模塊crete_loc_conf方法產生的結構體指針 void **loc_conf; //將同一個server塊內多個表達location塊的ngx_http_core_loc_conf_t結構體以雙向鏈表方式組織起來,該locations指向ngx_http_location_queue_t結構體 ngx_queue_t *locations; ... };
可以認為該結構體對應着當前解析的location塊,因為它已經擁有足夠的信息來表達一個location塊:它的loc_conf成員可以引用到個HTTP模塊在當前location塊中的配置項
其中ngx_http_location_queue_t結構的定義如下
typedef struct { //queue將作為ngx_queue_t雙向鏈表勇氣,從而將ngx_http_location_queue_t結構體連接起來 ngx_queue_t queue; //如果location中的字符串可以景區匹配,exact將指向對應的ngx_http_core_loc_conf_t結構體 ngx_http_core_loc_conf_t *exact; //如果location中的字符串無法精確匹配,inclusive將指向對應的ngx_http_core_conf_t結構體,否則為NULL ngx_http_core_loc_conf_t *inclusive; //指向location的名稱 ngx_str_t *name; ... } ngx_http_location_queue_t;
Nginx將ngx_http_core_loc_conf_t用雙向鏈表組織起來,也就是把location級別的配置項結構體管理起來了。
(其中所屬srv配置塊中ngx_http_core_module模塊在create_loc_conf方法中生成ngx_http_core_loc_conf_t結構體為鏈表的首元素),具體結構如下圖
合並不同級別的配置項
HTTP框架提供了merge_srv_conf方法用於合並main級別和srv級別的server相關的配置項,
同時,它還提供了merge_loc_conf方法用於合並main級別、srv級別、loc級別的location相關的配置項。
合並不同級別的配置項的步驟如下:
1.遍歷所有HTTP模塊,如果該模塊實現了merge_srv_conf方法,則調用該方法來合並main級別和srv級別的server相關的結構體;
2.遍歷所有HTTP模塊,如果該模塊實現了merge_loc_conf方法,先將main級別和srv級別的location相關的結構體合並,
然后將srv級別和loc級別的location相關的結構體合並。