Nginx的配置項(xiàng)
nginx 在每一個(gè)http 塊, server 塊, location 塊下, 都會(huì)生成獨(dú)立的數(shù)據(jù)結(jié)構(gòu)用來存放配置項(xiàng)
使用Http配置
- 處理http 配置項(xiàng)的基本流程:
- 創(chuàng)建數(shù)據(jù)結(jié)構(gòu), 存儲(chǔ)配置項(xiàng)參數(shù)
- 設(shè)定nginx.conf中配置項(xiàng)的限制條件與回掉方法
- 實(shí)現(xiàn)上一步中的回掉函數(shù), 或者使用預(yù)設(shè)的14種方法
- 合并不同級(jí)別的配置塊中出現(xiàn)的同名配置項(xiàng)
分配用于保存配置參數(shù)的數(shù)據(jù)結(jié)構(gòu)
- 數(shù)據(jù)結(jié)構(gòu)可以根據(jù)自己的項(xiàng)目的需求進(jìn)行定義, nginx有14 種預(yù)設(shè)配置項(xiàng), 設(shè)計(jì)了如下數(shù)據(jù)結(jié)構(gòu):
typedef struct {
ngx_str_t my_str;
ngx_int_t my_num;
ngx_flag_t my_flag;
size_t my_size;
ngx_array_t * my_str_array;
ngx_array_t * my_keyval;
off_t my_off;
ngx_msec_t my_msec;
time_t my_sec;
ngx_bufs_t my_bufs;
ngx_uint_t my_enum_seq;
ngx_uint_t my_bitmask;
ngx_uint_t my_access;
ngx_path_t * my_path;
} ngx_http_mytest_conf_t;
- nginx設(shè)計(jì)在HTTP 框架解析nginx.conf 文件的時(shí)候, 只要遇到 http{}, server{}, location{} 配置塊, 就會(huì)立即分配一個(gè)結(jié)構(gòu)體用來存儲(chǔ)配置參數(shù), 進(jìn)程中可能會(huì)有多個(gè)這樣的配置實(shí)例存在, 因而, 需要定義上述這個(gè)結(jié)構(gòu)體, 便于參數(shù)管理。通過ngx_http_module_t 中所定義的回調(diào)方法, 我們可以操作 這個(gè)結(jié)構(gòu)體 。
- 當(dāng)框架遇到 http{} 的時(shí)候, 調(diào)用HTTP 模塊可能實(shí)現(xiàn)的create_main_conf, create_srv_conf, create_loc_conf 生成存儲(chǔ)main級(jí)別配置參數(shù)的結(jié)構(gòu)體
- 同理,遇到 server{} 的時(shí)候, 調(diào)用 create_srv_conf, create_loc_conf 生成存儲(chǔ) srv 級(jí)別配置參數(shù)的結(jié)構(gòu)體
- 遇到 location{}時(shí), 調(diào)用 create_loc_conf 生成 loc 級(jí)別配置參數(shù)的存儲(chǔ)結(jié)構(gòu)
-
**一般普通的HTTP 模塊往往只實(shí)現(xiàn)create_loc_conf回調(diào)方法, 因?yàn)椋?他們一般只關(guān)心匹配某種URL的請(qǐng)求 **
設(shè)定配置項(xiàng)的解析方式
nginx中,配置項(xiàng)主要通過ngx_command_t結(jié)構(gòu)進(jìn)行解析。
關(guān)于type 的設(shè)置具體可以參考官方文檔: https://www.nginx.com/resources/wiki/extending/api/configuration/?highlight=ngx_command_t#
set 回調(diào)方法, 是用來處理nginx.conf 中的配置項(xiàng)的, 這部分可以使用14種預(yù)設(shè)的方法
-
conf, 用來指示配置項(xiàng)所處內(nèi)存的相對(duì)偏移位置。
- 因?yàn)椋?HTTP 模塊中可能定義了 3 個(gè)結(jié)構(gòu)體, 用來存儲(chǔ)main, srv, loc 級(jí)別的配置項(xiàng) (對(duì)應(yīng) create_main_conf, create_srv_conf, create_loc_conf), 這里使用 conf 用來指明, 將解析出來的配置項(xiàng)的值存放到哪個(gè)結(jié)構(gòu)體中
- 對(duì)conf 的設(shè)置是與ngx_http_module_t 實(shí)現(xiàn)的回調(diào)方法相關(guān)的。
- 功能較為簡(jiǎn)單的HTTP 模塊都只實(shí)現(xiàn)了create_loc_conf 的回調(diào)方法, 對(duì)于 http{}, server{} 塊內(nèi)出現(xiàn)的同名配置項(xiàng), 都是并入到某個(gè)location{} 內(nèi)create_loc_conf 方法所產(chǎn)生的結(jié)構(gòu)體中的。 如果希望, 在HTTP 模塊中的代碼保存到不同的變量中, 就需要實(shí)現(xiàn)create_mian_conf, create_srv_conf
offset, 用來表明當(dāng)前配置項(xiàng)在整個(gè)存儲(chǔ)配置項(xiàng)的結(jié)構(gòu)體中的偏移位置, 可以借助 offsetof 宏實(shí)現(xiàn)這個(gè)計(jì)算的過程
post, 配置項(xiàng)處理后的后續(xù)方法。
自定義配置項(xiàng)處理方法
- 首先自定義存儲(chǔ)結(jié)構(gòu)體
- 編寫set 方法
static char * ngx_conf_set_myconfig(ngx_conf_t * cf, ngx_command_t * cmd, void * conf);
- 其中, conf 指代的就是我們自定義的存儲(chǔ)結(jié)構(gòu)體 然后通過, cf->args->elfs 獲取參數(shù)隊(duì)列
static char* ngx_conf_set_myconfig(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
//注意,參數(shù)conf就是http框架傳給我們的,在ngx_http_mytest_create_loc_conf
//回調(diào)方法中分配的結(jié)構(gòu)體ngx_http_mytest_conf_t
ngx_http_mytest_conf_t *mycf = conf;
// cf->args是1個(gè)ngx_array_t隊(duì)列,它的成員都是ngx_str_t結(jié)構(gòu)。
//我們用value指向ngx_array_t的elts內(nèi)容,其中value[1]就是第1
//個(gè)參數(shù),同理value[2]是第2個(gè)參數(shù)
ngx_str_t* value = cf->args->elts;
//ngx_array_t的nelts表示參數(shù)的個(gè)數(shù)
if (cf->args->nelts > 1)
{
//直接賦值即可, ngx_str_t結(jié)構(gòu)只是指針的傳遞
mycf->my_config_str = value[1];
}
if (cf->args->nelts > 2)
{
//將字符串形式的第2個(gè)參數(shù)轉(zhuǎn)為整型
mycf->my_config_num = ngx_atoi(value[2].data, value[2].len);
//如果字符串轉(zhuǎn)化整型失敗,將報(bào)"invalid number"錯(cuò)誤,
//nginx啟動(dòng)失敗
if (mycf->my_config_num == NGX_ERROR)
{
return "invalid number";
}
}
//返回成功
return NGX_CONF_OK;
}
合并配置項(xiàng)
如果http{}, server{}, location{} 下面都出現(xiàn)了同名的配置項(xiàng), 根據(jù) merge_loc_conf(merge_srv_conf)進(jìn)行合并, 如果他們被設(shè)置為 null, * 忽略上一級(jí)中的同名配置項(xiàng) *
// cf 表示全局配置的設(shè)置, prev 表示父級(jí)配置結(jié)構(gòu)體, void * conf 為當(dāng)前配置結(jié)構(gòu)體
char * (*merge_loc_conf)(ngx_conf_t * cf, void * prev, void * conf)
HTTP 配置模型
- 當(dāng)nginx 檢測(cè)到 http{} 關(guān)鍵配置的時(shí)候, HTTP 配置模型啟動(dòng), 首先建立一個(gè)ngx_http_conf_ctx_t 的上下文結(jié)構(gòu)
typedef struct {
void ** main_conf;
void ** srv_conf;
void ** loc_conf; // 指針數(shù)組, 數(shù)組的每個(gè)元素指向相應(yīng) HTTP 模塊 的 create_loc_conf 方法產(chǎn)生的結(jié)構(gòu)體的地址
} ngx_http_conf_ctx_t;
HTTP 框架為所有的HTTP 模塊建立 3個(gè)數(shù)組, 分別存放 create_main_conf, create_srv_conf, create_loc_conf 方法所返回的地址指針。即ngx_http_conf_ctx_t 結(jié)構(gòu)保存了所有HTTP 模塊的配置數(shù)據(jù)結(jié)構(gòu)的入口。
解析HTTP 配置的流程
- 對(duì)于每一個(gè)server 塊, location 塊, http 塊 都會(huì)建立一個(gè)相應(yīng)的 ngx_http_conf_ctx_t 的結(jié)構(gòu)
HTTP配置模型的內(nèi)存結(jié)構(gòu)
- 通過上面的圖, 我們可以知道, nginx.conf中 http{}, server{}, location{} 的總個(gè)數(shù) 與 調(diào)用create_loc_conf方法的次數(shù)相同; 而 http{}, server{} 的總個(gè)數(shù) 與 調(diào)用create_srv_conf 方法的次數(shù)相同。 而這些方法每被調(diào)用一次就生成一個(gè)結(jié)構(gòu)體。 (便于解決同名配置項(xiàng)的合并問題)。
- 調(diào)用 merge_srv_conf, 和 merge_loc_conf 進(jìn)行配置項(xiàng)合并
預(yù)設(shè)配置項(xiàng)處理方法的工作原理
- 通過 使用 cf->args->elts 直接獲取配置參數(shù)
- nginx 配置項(xiàng)解析模塊在調(diào)用 ngx_command_t 結(jié)構(gòu)體的set 方法的時(shí)候, 會(huì)同時(shí)把offset 編譯傳遞進(jìn)來。由此, 可以正確識(shí)別需要解析的配置項(xiàng)的存儲(chǔ)位置
error日志
- 可以使用 ngx_log_error / ngx_log_debug 進(jìn)行日志記錄
請(qǐng)求上下文
- 在一個(gè)請(qǐng)求的處理過程中, 用類似struct 這樣的結(jié)構(gòu)體把一些關(guān)鍵的信息保存起來的結(jié)構(gòu)體, 稱為上下文上下文是針對(duì)一個(gè)請(qǐng)求 一個(gè)模塊而言的, 因而他是低耦合的
-
使用方法:
- 兩個(gè)宏:
- ngx_http_get_module_ctx
- ngx_http_set_ctx
-
一般的調(diào)用方式是:
可以看到這里先設(shè)置了上下文,然后后面就可以獲取它并進(jìn)行使用
- HTTP 框架維護(hù)上下文結(jié)構(gòu)的方式
- 類似于ngx_http_conf_ctx_t 的 3 個(gè)數(shù)組成員, HTTP 框架 使用 ctx 數(shù)組 保存所有 HTTP 模塊上下文結(jié)構(gòu)體的指針
- 兩個(gè)宏:
struct ngx_http_request_s {
...
void ** ctx;
...
}
```
- ngx_http_get_module_ctx 和 ngx_http_set_ctx 的原理就是去獲取或設(shè)置 ctx 數(shù)組中相應(yīng)的 HTTP 模塊的指針