原创:https://blog.csdn.net/ndzjx/article/details/89502852
配置:
处理HTTP配置项分为4个步骤:
1)创建数据结构用于存储配置项对应的参数。
2)设定配置项在nginx.conf中出现时的限制条件与回调方法。
3)实现第2步中的回调方法,或者使用Nginx框架预设的14个回调方法。
4)合并不同级别的配置块中出现的同名配置项
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_unit_t my_bitmask;
ngx_uint_t my_access;
ngx_path_t *my_path;
}ngx_http_mytest_conf_t;
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;
其中create_main_conf、create_srv_conf、create_loc_conf三个回调方法负责把我们分配的用于保存配置项的结构体传递给HTTP框架。
这里实现create_loc_conf的是:
static void *
ngx_http_mytest_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_mytest_conf_t *mycf;
mycf = (ngx_http_mytest_conf_t *)ngx_pcalloc(cf->pool, sizeof(ngx_http_mytest_conf_t));
if (mycf == NULL) {
return NULL;
}
// 以下几个类型的值因为其对应的默认解析方法,要对应设置初始值。
mycf->my_flag = NGX_CONF_UNSET;
mycf->my_num = NGX_CONF_UNSET;
mycf->my_str_array = NGX_CONF_UNSET_PTR;
mycf->my_keyval = NULL;
mycf->my_off = NGX_CONF_UNSET;
mycf->my_msec = NGX_CONF_UNSET_MSEC;
mycf->my_sec = NGX_CONF_UNSET;
mycf->my_size = NGX_CONF_UNSET_SIZE;
return mycf;
}
合并配置项:(以ngx_str_t my_str为例)
这里实现merge_loc_conf的是: 这里决定不同级别的同名配置项冲突时的解决方案
static char *
ngx_http_mytest_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_mytest_conf_t *prev = (ngx_http_mytest_conf_t *)parent;
ngx_http_mytest_conf_t *conf = (ngx_http_mytest_conf_t *)child;
/* Nginx预设了10种配置项合并宏 */
ngx_conf_merge_str_value(conf->my_str, prev->my_str, "defaultstr");
return NGX_CONF_OK;
}
struct ngx_command_s {
ngx_str_t name; // 配置项的名称
ngx_uint_t type; //决定配置项可以在哪些块,以及可以携带的参数个数和类型
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
ngx_uint_t conf; // 指示配置项所处内存的相对偏移位置。HTTP模块会定义三个结构体,HTTP框架需要知道配置项值写入那个结构体中,这将由conf成员完成。
ngx_uint_t offset; // 表示当前配置项在整个存储配置项的结构体中的偏移位置offsetof
void *post;
};
每个进程都有一个ngx_cycle_t核心结构体,有一个成员void ****conf_ctx ,NGX_CORE_MODULE类型的核心块解析配置项时,不需要双数组设计(核心模块本身就是第一层数组),会把void ****转化为void **,直接指向核心模块生成的配置结构体,因此NGX_DIRECT_CONF仅由NGX_CORE_MODULE类型的核心模块使用,该配置项只出现在全局配置中。
配置项出现的位置与参数格式与type的意义不符时,Nginx启动会报错。
可以使用预设的14中方法解析配置项,预设的方法根据offset确定变量的位置。
也可以自定义方法来解析:
假设我们要处理的配置项为test_config,接受1个或2个参数,定义结构体来存储这两个参数:
typedef struct {
ngx_str_t my_config_str;
ngx_int_t my_config_num;
} ngx_http_mytest_conf_t;
static ngx_command_t ngx_http_mytest_commands[] = {
{ ngx_string(“test_myconfig”),
NGX_HTTP_LOC_CONF | NGX_CONF_TAKE12,
ngx_conf_set_myconfig,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
ngx_null_command
};
static *
ngx_conf_set_myconfig(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_mytest_conf_t *mycf = conf;
/* cf->args是一个ngx_array_t队列,成员时ngx_str_t结构,用value指向ngx_array_t
的elts内容,其中value[1]就是第一个参数,value[2]是第2个参数*/
ngx_str_t *value = cf->args->elts;
if (cf->args->nelts > 1)
{
mycf->my_config_str = value[1];
}
if (cf->args->nelts > 2)
{
mycf->my_config_num = ngx_atoi(value[2].data, value[2].len);
if (mycf->my_config_num == NGX_ERROR) {
return "invalid number";
}
}
return NGX_CONF_OK;
}
error日志的用法:
两个宏:
ngx_log_error
ngx_log_debug 中level表示日志的类型
%V ---ngx_str_t
%i ---ngx_int_t
%d ---int
%D --- int32_t
%L ---int64_t
如:
ngx_log_error(NGX_LOG_ALERT, cf→log, 0, “D=%D”,&ti32);
请求的上下文:
HTTP框架定义的上下文是针对于HTTP请求的。保存请求中关键的信息。
Nginx是全异步的Web服务器,1个请求不会在epoll的1次调用中处理完成,甚至要成千上万次的调度HTTP模块后才能完成请求的处理,所有要有上下文的概念。
#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;