转:nginx模块开发——handler(二)
模块上下文结构
这是一个ngx_http_module_t类型的静态变量。这个变量实际上是提供一组回调函数指针,这些函数有在创建存储配置信息的对象的函数,也有在创建前和创建后会调用的函数。这些函数都将被nginx在合适的时间进行调用。
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 preconfiguration: 在创建和读取该模块的配置信息之前被调用。 2 postconfiguration: 在创建和读取该模块的配置信息之后被调用。 3 create_main_conf: 调用该函数创建本模块位于http block的配置信息存储结构。该函数成功的时候,返回创建的配置对象。失败的话,返回NULL。 4 init_main_conf: 调用该函数初始化本模块位于http block的配置信息存储结构。该函数成功的时候,返回NGX_CONF_OK。失败的话,返回NGX_CONF_ERROR或错误字符串。 5 create_srv_conf: 调用该函数创建本模块位于http server block的配置信息存储结构,每个server block会创建一个。该函数成功的时候,返回创建的配置对象。失败的话,返回NULL。 6 merge_srv_conf: 因为有些配置指令即可以出现在http block,也可以出现在http server block中。那么遇到这种情况,每个server都会有自己存储结构来存储该server的配置,但是在这种情况下当在http block中的配置与server block中的配置信息冲突的时候,就需要调用此函数进行合并,该函数并非必须提供,当预计到绝对不会发生需要合并的情况的时候,就无需提供。当然为了安全期间还是建议提供。该函数成功的时候,返回NGX_CONF_OK。失败的话,返回NGX_CONF_ERROR或错误字符串。 7 create_loc_conf: 调用该函数创建本模块位于location block的配置信息存储结构。每个在配置中指明的location创建一个。该函数成功的时候,返回创建的配置对象。失败的话,返回NULL。 8 merge_loc_conf: 与merge_srv_conf类似,这个也是进行配置值合并的地方。该函数成功的时候,返回NGX_CONF_OK。失败的话,返回NGX_CONF_ERROR或错误字符串。
Nginx里面的配置信息都是上下一层层的嵌套的,对于具体某个location的话,对于同一个配置,如果自己这里没有定义,那么就使用上层的配置,否则是用自己的配置。这些配置信息一般默认都应该设为一个未初始化的值,针对这个需求,Nginx定义了一系列的宏定义来代表个中配置所对应数据类型的未初始化值,如下:
#define NGX_CONF_UNSET -1 #define NGX_CONF_UNSET_UINT (ngx_uint_t) -1 #define NGX_CONF_UNSET_PTR (void *) -1 #define NGX_CONF_UNSET_SIZE (size_t) -1 #define NGX_CONF_UNSET_MSEC (ngx_msec_t) -1
又因为对于配置项的合并,逻辑都类似,也就是前面已经说过的,如果在本层次已经配置了,也就是配置项的值已经被读取进来了(那么这些配置项的值就不会等于上面已经定义的那些UNSET的值),就使用本层次的值作为定义合并的结果,否则,使用上层的值,如果上层的值也是这些UNSET类的值,那就复制为默认值,否则就是用上层的值作为合并的结果。对于这样类似的操作,Nginx定义了一些宏操作来做这些事情,我们来看其中一个的定义。
#define ngx_conf_merge_uint_value(conf, prev, default) \ if (conf == NGX_CONF_UNSET_UINT) { \ conf = (prev == NGX_CONF_UNSET_UINT) ? default : prev; \ }
显而易见,这个逻辑确实比较简单,所以其它的宏定义也类似,我们就列具其中的一部分吧。
ngx_conf_merge_value
ngx_conf_merge_ptr_value
ngx_conf_merge_uint_value
ngx_conf_merge_msec_value
ngx_conf_merge_sec_value
下面来看一下hello模块的模块上下文的定义,加深一下印象。
static ngx_http_module_t ngx_http_hello_module_ctx = { NULL, /* preconfiguration */ ngx_http_hello_init, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ NULL, /* create server configuration */ NULL, /* merge server configuration */ ngx_http_hello_create_loc_conf, /* create location configuration */ NULL /* merge location configuration */ };
注意:这里并没有提供merge_loc_conf函数,因为我们这个模块的配置指令已经确定只出现在NGX_HTTP_LOC_CONF中这一个level上,不会发生需要合并的情况。