1 定义 static char * ngx_http_merge_servers ( ngx_conf_t * cf, ngx_http_core_main_conf_t * cmcf, ngx_http_module_t * module, ngx_uint_t ctx_index) { char * rv; ngx_uint_t s; ngx_http_conf_ctx_t * ctx, saved; ngx_http_core_loc_conf_t * clcf; ngx_http_core_srv_conf_t * * cscfp; cscfp= cmcf-> servers. elts; ctx= ( ngx_http_conf_ctx_t * ) cf-> ctx; saved= * ctx; rv= NGX_CONF_OK; for ( s= 0 ; s< cmcf-> servers. nelts; s++ ) { /* merge the server{}s' srv_conf's */ ctx-> srv_conf= cscfp[ s] -> ctx-> srv_conf; if ( module-> merge_srv_conf) { rv= module-> merge_srv_conf ( cf, saved. srv_conf[ ctx_index] , cscfp[ s] -> ctx-> srv_conf[ ctx_index] ) ; if ( rv!= NGX_CONF_OK) { goto failed; } } if ( module-> merge_loc_conf) { /* merge the server{}'s loc_conf */ ctx-> loc_conf= cscfp[ s] -> ctx-> loc_conf; rv= module-> merge_loc_conf ( cf, saved. loc_conf[ ctx_index] , cscfp[ s] -> ctx-> loc_conf[ ctx_index] ) ; if ( rv!= NGX_CONF_OK) { goto failed; } /* merge the locations{}' loc_conf's */ clcf= cscfp[ s] -> ctx-> loc_conf[ ngx_http_core_module. ctx_index] ; rv= ngx_http_merge_locations ( cf, clcf-> locations, cscfp[ s] -> ctx-> loc_conf, module, ctx_index) ; if ( rv!= NGX_CONF_OK) { goto failed; } } } failed: * ctx= saved; return rv; } `ngx_http_merge_servers` 函数用于 将指定 HTTP 模块的配置从主配置(`main`)合并到各个 `server` 块以及它们内部的 `location` 块中。2 详解 1 函数签名 static char * ngx_http_merge_servers ( ngx_conf_t * cf, ngx_http_core_main_conf_t * cmcf, ngx_http_module_t * module, ngx_uint_t ctx_index) 返回值 返回一个指向字符串的指针。 成功时返回 NGX_CONF_OK,该宏被定义为 (char *) NULL。 如果合并过程中发生错误,则返回一个指向错误信息字符串的指针参数 ngx_conf_t *cf 当前配置解析上下文 ngx_http_core_main_conf_t *cmcf 指向 HTTP 核心模块的主配置结构体 ngx_http_module_t *module 指向 http 模块的定义 ngx_uint_t ctx_index 当前模块的配置结构体在 srv_conf 和 loc_conf 数组中的位置索引2 逻辑流程 1 局部变量 2 变量初始化 3 遍历每个 server {} 块 3-1 切换 Server 配置上下文 3-2 检查并调用 Server 合并回调 3-3 检查并准备合并 Location 配置 3-4 递归合并该 server 内部的所有 location 块 4 错误处理 5 返回处理结果1 局部变量{ char * rv; ngx_uint_t s; ngx_http_conf_ctx_t * ctx, saved; ngx_http_core_loc_conf_t * clcf; ngx_http_core_srv_conf_t * * cscfp; 2 变量初始化cscfp= cmcf-> servers. elts; ctx= ( ngx_http_conf_ctx_t * ) cf-> ctx; saved= * ctx; rv= NGX_CONF_OK; #1 获取 cmcf(HTTP 核心主配置)中 servers 数组的元素指针,并赋值给 cscfp。 cmcf 是 ngx_http_core_main_conf_t 结构体,代表 http {} 块的核心配置。 cmcf->servers 是一个 ngx_array_t 类型的动态数组, 里面存储了所有解析出来的 server {} 块的配置上下文指针。 .elts 是 Nginx 数组结构体中指向实际数据内存块的指针。 cscfp 的类型是 ngx_http_core_srv_conf_t **,即“服务器核心配置指针的数组”。 意义: 获取遍历入口。 Nginx 支持配置多个虚拟主机(多个 server {}), 这行代码拿到了所有虚拟主机配置列表的起始地址, 使得后续的 for 循环可以通过下标 s 访问每一个 server {} 的配置。#2 cf: 当前配置上下文,类型为 ngx_conf_t *,包含解析器状态、内存池、当前指令参数等。 cf->ctx: void * 类型,指向当前配置层级的上下文。 在 HTTP 模块中,该上下文实际是 ngx_http_conf_ctx_t 结构体。 ngx_http_conf_ctx_t: 包含了三个指针数组 main_conf、srv_conf、loc_conf, 分别存储各模块在 main、server、location 级别的配置。 强制类型转换:将 cf->ctx 转换为 ngx_http_conf_ctx_t * 并赋值给 ctx。 意义: 将当前解析器上下文的通用指针转换为 HTTP 模块可用的具体结构体指针,以便访问各模块的配置数组。#3 saved 在函数开头声明为 ngx_http_conf_ctx_t saved;(结构体变量,非指针)。 操作:将 ctx 指向的整个 ngx_http_conf_ctx_t 结构体的内容拷贝到 saved 中。 意义: 保存原始上下文。 在后续遍历每个 server 时,会临时修改 ctx 所指向的结构体, 通过保存副本,可以在函数结束或出错时恢复上下文,避免影响其他模块或其他操作。#4 rv 是函数的返回值, 类型 char * NGX_CONF_OK 宏定义为 (char *) NULL,表示成功。 意义:初始化返回值为成功状态。 后续如果任何合并操作失败,会将 rv 设置为具体的错误字符串(非空), 并跳转到错误处理。最后返回 rv 供上层判断。3 遍历每个 server {} 块for ( s= 0 ; s< cmcf-> servers. nelts; s++ ) { /* merge the server{}s' srv_conf's */ 3-1 切换 Server 配置上下文ctx-> srv_conf= cscfp[ s] -> ctx-> srv_conf; 修改全局上下文 ctx 中的 srv_conf 指针,使其指向当前循环到的第 s 个 server {} 块的 srv_conf 配置数组。 cscfp[s] 是第 s 个 server 的核心配置(ngx_http_core_srv_conf_t *) cscfp[s]->ctx 是该 server 自己的上下文(ngx_http_conf_ctx_t *), 其中包含了该 server 的 srv_conf 和 loc_conf 数组。 通过赋值,使得后续通过 ctx->srv_conf 访问到的配置就是当前 server 的配置3-2 检查并调用 Server 合并回调if ( module-> merge_srv_conf) { rv= module-> merge_srv_conf ( cf, saved. srv_conf[ ctx_index] , cscfp[ s] -> ctx-> srv_conf[ ctx_index] ) ; if ( rv!= NGX_CONF_OK) { goto failed; } } #1 检查当前模块是否提供了 merge_srv_conf 回调函数。 如果该函数指针非空,则说明模块需要合并 server 级配置,执行合并;否则跳过。#2 调用模块的 merge_srv_conf 函数,将主配置(父级)与当前 server 的配置(子级)合并。 参数: cf:配置上下文。 saved.srv_conf[ctx_index]: 父级配置,即主层级(http 块)的默认配置。 cscfp[s]->ctx->srv_conf[ctx_index]: 子级配置,即当前 server 的配置(可能覆盖父级)。 意义:完成 server 级配置的继承与合并,结果将用于该 server 的最终配置。#3 如果合并过程中出现错误,立即进入错误处理流程。3-3 检查并准备合并 Location 配置if ( module-> merge_loc_conf) { /* merge the server{}'s loc_conf */ ctx-> loc_conf= cscfp[ s] -> ctx-> loc_conf; rv= module-> merge_loc_conf ( cf, saved. loc_conf[ ctx_index] , cscfp[ s] -> ctx-> loc_conf[ ctx_index] ) ; if ( rv!= NGX_CONF_OK) { goto failed; } #1 检查模块是否提供了 merge_loc_conf 回调函数。 如果存在,则需要进行 location 级别的配置合并。 模块可能只关心 server 级配置而不关心 location 级,通过判断避免无谓操作#2 将当前上下文 ctx 的 loc_conf 指针指向当前 server 的 loc_conf 数组#3 调用模块的 merge_loc_conf 函数, 合并 server 级别的 location 配置(即 server 块中直接出现的与 location 相关的指令) 参数: cf:配置上下文。 saved.loc_conf[ctx_index]: 父级(主层级)的 location 配置。 cscfp[s]->ctx->loc_conf[ctx_index]: 当前 server 的 location 配置。 合并后得到该 server 上 location 级指令的最终配置(此配置将作为 server 下所有 location 的默认父配置)。 完成 server 级 location 配置的继承,为后续 location 块合并提供正确的父级配置。3-4 递归合并该 server 内部的所有 location 块/* merge the locations{}' loc_conf's */ clcf= cscfp[ s] -> ctx-> loc_conf[ ngx_http_core_module. ctx_index] ; rv= ngx_http_merge_locations ( cf, clcf-> locations, cscfp[ s] -> ctx-> loc_conf, module, ctx_index) ; if ( rv!= NGX_CONF_OK) { goto failed; } } } #1 获取当前 server 的核心模块(ngx_http_core_module)的 location 配置结构体 从当前 server 的 loc_conf 数组中,取出 HTTP Core 模块 的配置结构体。 loc_conf 是一个数组,存放了所有 HTTP 模块的配置指针。 ngx_http_core_module.ctx_index 是 Core 模块的固定索引。 clcf (ngx_http_core_loc_conf_t *) 是核心 location 级配置, 它包含了 locations 字段,这是一个树状结构,存储了该 server 下所有显式定义的 location {} 块。 获取 location 树。 只有 Core 模块维护了 location {} 的拓扑结构(前缀匹配、正则匹配等)。 其他业务模块(如 gzip)只关心配置数据,不关心 location 结构, 所以必须从 Core 模块获取 locations 树来进行递归合并。#2 调用 ngx_http_merge_locations 函数, 递归合并该 server 下所有 location 块的配置。 参数: cf:配置上下文 clcf->locations: location 树的队列头,包含了所有顶层 location 块。 cscfp[s]->ctx->loc_conf: 当前 server 的 location 配置数组, 作为所有 location 的父级配置(默认值)。 module: 当前模块。 ctx_index: 模块索引。 该函数会遍历每个 location 块, 对每个 location 调用 merge_loc_conf, 并递归处理嵌套 location,实现完整的 location 配置合并。#3 检查递归合并的结果。 出错时跳转到错误处理。4 错误处理failed: * ctx= saved; 恢复 原始上下文5 返回处理结果return rv; }