nginx模块开发入门(四)-2.3 The Module Context

2.3.模块上下文(TheModuleContext)

静态的ngx_http_module_t结构体,包含一大坨函数引用,用来创建和合并三段配置(main,server,location),命名方式一般是:ngx_http_<modulename>_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配置时调用

函数的入参各不相同,取决于他们具体要做的事情。这里http/ngx_http_config.h是结构体的具体定义:

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;

可以把不需要的函数设置为NULL,Nginx会忽略掉他们。

绝大多数的handler只使用最后两个:一个用来为特定location配置来分配内存,(叫做ngx_http_<modulename>_create_loc_conf),另一个用来设定默认值以及合并继承过来的配置值(叫做ngx_http_<modulename>_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都会用到这个部分,所以值得好好看看。

2.3.1.create_loc_conf

下面这段摘自我自己写的模块circle_gif(源代码),create_loc_conf的骨架大概就是这个样子.它的入参是(ngx_conf_t),返回值是更新了的模块配置结构体(在这里是ngx_http_circle_gif_loc_conf_t).

static void *
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的包装函数),就不用担心内存的释放了。

UNSET可能的常量有NGX_CONF_UNSET_UINT,NGX_CONF_UNSET_PTR,NGX_CONF_UNSET_SIZE,NGX_CONF_UNSET_MSEC,以及无所不包的NGX_CONF_UNSET,UNSET让合并函数知道哪些变量是需要覆盖的。

2.3.2.merge_loc_conf

下面的例子是我的模块circle_gif中的合并函数:

static char *
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_<datatype>_value),这类函数的入参是:

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

1.当前location的变量值

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

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

结果会被保存在第一个参数中。能用的合并函数包括ngx_conf_merge_size_value,ngx_conf_merge_msec_value等等.可参见core/ngx_conf_file.h.

引用

问:第一个参数是传值的,那如何能做到将结果保存到第一个参数中?

答:这些函数都是由预处理命令定义的(在真正编译之前,它们会被扩展成一些if语句)

同时还需要注意的是错误的产生。函数会往log文件写一些东西,同时返回NGX_CONF_ERROR。这个返回值会将server的启动挂起。(因为被标示为NGX_LOG_EMERG级别,所以错误同时还会输出到标准输出。作为参考,core/ngx_log.h列出了所有的日志级别。)

相关推荐