Emiller的Nginx模块开发指南中文版(3)

NGX_CONF_2MORE: 指令至少读入2个参数

这里还有很多其他的选项:. 结构体成员 set 是一个函数指针,它指向的函数用来进行模块配置;这个设定函数一般用来将配置文件中的参数传递给程序,并保存在配置结构体中。设定函数有三个入参:

指向结构体 ngx_conf_t 的指针, 这个结构体里包含需要传递给指令的参数

指向结构体 ngx_command_t 的指针

指向模块自定义配置结构体的指针

设定函数会在遇到指令时执行,Nginx提供了多个函数用来保存特定类型的数据,这些函数包含有:

ngx_conf_set_flag_slot: 将 "on" or "off" 转换成 1 or 0

ngx_conf_set_str_slot: 将字符串保存为 ngx_str_t

ngx_conf_set_num_slot: 解析一个数字并保存为int

ngx_conf_set_size_slot: 解析一个数据大小(如:"8k", "1m") 并保存为size_t

当然还有其他的,在中很容易查到。如果你觉得现有这些内置的函数还不能满足你,当然也可以传入自己的函数引用。 这些内置函数是如何知道把数据存放在哪里的呢?这就是接下来两个结构体成员 conf 和 offset要做的事了. conf 告诉Nginx把数据存在模块的哪个配置中,是main配置、server 配置, 还是 location 配置 ?(通过 NGX_HTTP_MAIN_CONF_OFFSET, NGX_HTTP_SRV_CONF_OFFSET, 或者 NGX_HTTP_LOC_CONF_OFFSET). offset 确定到底是保存在结构体的哪个位置。 最后, post指向模块在读配置的时候需要的一些零碎变量。一般它是NULL。 ngx_command_t数组以ngx_null_command 为终结符(就好像字符串以'\0'为终结符一样). 3.3. 模块上下文 静态的ngx_http_module_t结构体,包含一大坨函数引用,用来创建和合并三段配置(main,server,location),命名方式一般是:ngx_http_<module name>_module_ctx. 这些函数引用依次是:

preconfiguration 在读入配置前调用

postconfiguration 在读入配置后调用

create_main_conf 在创建main配置时调用(比如,用来分配空间和设置默认值)

init_main_conf 在初始化main配置时调用(比如,把原来的默认值用nginx.conf读到的值来覆盖)

init_main_conf 在创建server配置时调用

merge_srv_conf 合并server和main配置时调用

create_loc_conf 创建location配置时调用

merge_loc_conf 合并location和server配置时调用

函数的入参各不相同,取决于他们具体要做的事情。这里是结构体的具体定义: typedefstruct{
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; 可以把你不需要的函数设置为NULL,Nginx会忽略掉他们。 绝大多数的 handler只使用最后两个: 一个用来为特定location配置来分配内存,(叫做 ngx_http_<module name>_create_loc_conf), 另一个用来设定默认值以及合并继承过来的配置值(叫做 ngx_http_<module name >_merge_loc_conf)。合并函数同时还会检查配置的有效性,如果有错误,则server的启动将被挂起。 下面是一个使用模块上下文结构体的例子: static ngx_http_module_t ngx_http_circle_gif_module_ctx ={
NULL
,/* preconfiguration */
NULL
,/* postconfiguration */

NULL
,/* create main configuration */
NULL
,/* init main configuration */

NULL
,/* create server configuration */
NULL
,/* merge server configuration */

ngx_http_circle_gif_create_loc_conf
,/* create location configuration */
ngx_http_circle_gif_merge_loc_conf
/* merge location configuration */
}; 现在开始讲得更深一点。这些配置回调函数看其来很像,所有模块都一样,而且Nginx的API都会用到这个部分,所以值得好好看看。 3.3.1. create_loc_conf 下面这段摘自我自己写的模块circle_gif(源代码),create_loc_conf的骨架大概就是这个样子. 它的入参是(ngx_conf_t),返回值是更新了的模块配置结构体(在这里是 ngx_http_circle_gif_loc_conf_t). staticvoid*
ngx_http_circle_gif_create_loc_conf
(ngx_conf_t *cf)
{
ngx_http_circle_gif_loc_conf_t
*conf;

conf
= ngx_pcalloc(cf->pool,sizeof(ngx_http_circle_gif_loc_conf_t));
if(conf == NULL){
return NGX_CONF_ERROR;
}
conf
->min_radius = NGX_CONF_UNSET_UINT;
conf
->max_radius = NGX_CONF_UNSET_UINT;
return conf;
} 首先需要指出的是Nginx的内存分配;只要使用了 ngx_palloc(malloc的一个包装函数)或者 ngx_pcalloc (calloc的包装函数),就不用担心内存的释放了。(TODO: to see why?) UNSET可能的常量有NGX_CONF_UNSET_UINT, NGX_CONF_UNSET_PTR, NGX_CONF_UNSET_SIZE, NGX_CONF_UNSET_MSEC,以及无所不包的NGX_CONF_UNSET,UNSET让合并函数知道哪些变量是需要覆盖的。 3.3.2. merge_loc_conf 下面的例子是我的模块circle_gif中的合并函数: staticchar*
ngx_http_circle_gif_merge_loc_conf
(ngx_conf_t *cf,void*parent,void*child)
{
ngx_http_circle_gif_loc_conf_t
*prev = parent;
ngx_http_circle_gif_loc_conf_t
*conf = child;

ngx_conf_merge_uint_value
(conf->min_radius, prev->min_radius,10);
ngx_conf_merge_uint_value
(conf->max_radius, prev->max_radius,20);

if(conf->min_radius <1){
ngx_conf_log_error
(NGX_LOG_EMERG, cf,0,
"min_radius must be equal or more than 1");
return NGX_CONF_ERROR;
}
if(conf->max_radius < conf->min_radius){
ngx_conf_log_error
(NGX_LOG_EMERG, cf,0,
"max_radius must be equal or more than min_radius");
return NGX_CONF_ERROR;
}

return NGX_CONF_OK;
} 这里的需要注意的是Nginx提供了一些好用的合并函数用来合并不同类型的数据(ngx_conf_merge_<data type>_value),这类函数的入参是:

当前location的变量值

如果第一个参数没有被设置而采用的值

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/19fc7ad62f46cc42880e39dcf6c03d4a.html