首页 > 代码库 > 【Nginx】HTTP配置模型

【Nginx】HTTP配置模型

当Nginx检测到配置文件中存在配置块http{}时,会建立一个ngx_http_conf_ctx_t结构体,该结构体定义如下:

typedef struct {
    void        **main_conf;    // 每个指针元素指向所有由HTTP模块的create_main_conf方法产生的结构体
    void        **srv_conf;     // 每个指针元素指向所有由HTTP模块的create_srv_conf方法产生的结构体
    void        **loc_conf;     // 每个指针元素指向所有由HTTP模块的create_loc_conf方法产生的结构体
} ngx_http_conf_ctx_t;


具体来说,框架代码在遇到http{}时会调用核心模块ngx_http_module(HTTP框架的一部分)中解析配置项的ngx_http_block方法,该方法的关于生成和配置ngx_http_conf_ctx_t结构体的过程大致如下,代码位于ngx_http.c中:
ngx_http_conf_ctx_t  *ctx;     // 定义一个该结构体的指针
 
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));     // 分配该结构体空间

ctx->main_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);     // 分配数组存放指针
ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);      // 分配数组存放指针
ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);      // 分配数组存放指针
 
for (m = 0; ngx_modules[m]; m++)
{
    if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
        continue;
    }
 
    module = ngx_modules[m]->ctx;
    mi = ngx_modules[m]->ctx_index;
 
    if (module->create_main_conf)
    {
        /* 依次调用所有HTTP模块的create_main_conf方法
         * 产生的结构体指针放入上面分配了空间的main_conf指针数组中
         */
        ctx->main_conf[mi] = module->create_main_conf(cf);
        if (ctx->main_conf[mi] == NULL)
        {
            return NGX_CONF_ERROR;
        }
    }
 
    if (module->create_srv_conf)
    {
        /* 依次调用所有HTTP模块的create_srv_conf方法
         * 产生的结构体指针放入上面分配了空间的srv_conf指针数组中
         */
        ctx->srv_conf[mi] = module->create_srv_conf(cf);
        if (ctx->srv_conf[mi] == NULL)
        {
             return NGX_CONF_ERROR;
        }
    }
 
    if (module->create_loc_conf)
    {
        /* 依次调用所有HTTP模块的create_loc_conf方法
         * 产生的结构体指针放入上面分配了空间的loc_conf指针数组中
         */
        ctx->loc_conf[mi] = module->create_loc_conf(cf);
        if (ctx->loc_conf[mi] == NULL)
        {
            return NGX_CONF_ERROR;
        }
    }
}


server{}和location{}和http{}相似:
  • 当遇到server{}配置块时,建立ngx_http_conf_ctx_t结构体,main_conf成员指向父配置块所对应的ngx_http_conf_ctx_t结构体,srv_conf成员和loc_conf成员存储HTTP模块通过create_srv_conf和create_loc_conf方法产生的配置结构体指针。
  • 当遇到location{}配置块时,建立ngx_http_conf_ctx_t结构体,main_conf成员指向父配置块对应ngx_http_conf_ctx_t结构体,srv_conf成员指向父配置块ngx_http_conf_ctx_t结构体的srv_conf元素,loc_conf存储HTTP模块create_loc_conf方法产生的配置结构体指针。
三个ngx_http_conf_ctx_t结构体分别对应http{}、server{}、location{},它们之间的关系用下图可以清晰的说明:


下面介绍解析HTTP配置的大致流程:
  1. Nginx进程主循环调用配置文件解析器解析nginx.conf配置文件。
  2. 配置文件解析器发现http{},启动HTTP框架,也就是核心模块ngx_http_module。
  3. 核心模块调用ngx_command_t中的set回调函数,也就是ngx_http_block方法。
  4. 初始化所有HTTP模块的序号,分配一个ngx_http_conf_ctx_t结构体并初始化三个数组。
  5. 调用每个HTTP模块的create_main_conf、create_srv_conf、create_loc_conf方法分配存储配置项参数的结构体,返回的指针保存在ngx_http_conf_ctx_t结构体中。
  6. 调用每个HTTP模块的preconfiguration方法。
  7. 配置文件解析器检测到一个配置项后,遍历所有HTTP模块的ngx_command_t数组,看有没有能够和配置项名称匹配的ngx_command_t结构体,有则调用ngx_command_t结构中的set方法来处理配置项。
  8. 配置文件解析器继续检测配置项,遇到server{}或location{}则以类似的方法递归解析块中的配置项,不过此时负责解析配置项的模块变成了ngx_http_core_module,方法在上面已经详细说明了。
  9. 配置文件解析器解析到http{}尾端,返回HTTP框架ngx_http_module。
  10. 调用merge_srv_conf和merge_loc_conf等方法合并配置项结构体。
  11. HTTP框架处理完http配置项,ngx_command_t的set回调方法返回。
  12. 配置文件解析器返回Nginx主循环,Nginx进程启动Web服务器。
参考:
《深入理解Nginx》 P140-P143.