1. 定义


./nginx-1.24.0/src/core/ngx_conf_file.c

static ngx_int_t
ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)
{
    char           *rv;
    void           *conf, **confp;
    ngx_uint_t      i, found;
    ngx_str_t      *name;
    ngx_command_t  *cmd;

    name = cf->args->elts;

    found = 0;

    for (i = 0; cf->cycle->modules[i]; i++) {

        cmd = cf->cycle->modules[i]->commands;
        if (cmd == NULL) {
            continue;
        }

        for ( /* void */ ; cmd->name.len; cmd++) {

            if (name->len != cmd->name.len) {
                continue;
            }

            if (ngx_strcmp(name->data, cmd->name.data) != 0) {
                continue;
            }

            found = 1;

            if (cf->cycle->modules[i]->type != NGX_CONF_MODULE
                && cf->cycle->modules[i]->type != cf->module_type)
            {
                continue;
            }

            /* is the directive's location right ? */

            if (!(cmd->type & cf->cmd_type)) {
                continue;
            }

            if (!(cmd->type & NGX_CONF_BLOCK) && last != NGX_OK) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                  "directive \"%s\" is not terminated by \";\"",
                                  name->data);
                return NGX_ERROR;
            }

            if ((cmd->type & NGX_CONF_BLOCK) && last != NGX_CONF_BLOCK_START) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "directive \"%s\" has no opening \"{\"",
                                   name->data);
                return NGX_ERROR;
            }

            /* is the directive's argument count right ? */

            if (!(cmd->type & NGX_CONF_ANY)) {

                if (cmd->type & NGX_CONF_FLAG) {

                    if (cf->args->nelts != 2) {
                        goto invalid;
                    }

                } else if (cmd->type & NGX_CONF_1MORE) {

                    if (cf->args->nelts < 2) {
                        goto invalid;
                    }

                } else if (cmd->type & NGX_CONF_2MORE) {

                    if (cf->args->nelts < 3) {
                        goto invalid;
                    }

                } else if (cf->args->nelts > NGX_CONF_MAX_ARGS) {

                    goto invalid;

                } else if (!(cmd->type & argument_number[cf->args->nelts - 1]))
                {
                    goto invalid;
                }
            }

            /* set up the directive's configuration context */

            conf = NULL;

            if (cmd->type & NGX_DIRECT_CONF) {
                conf = ((void **) cf->ctx)[cf->cycle->modules[i]->index];

            } else if (cmd->type & NGX_MAIN_CONF) {
                conf = &(((void **) cf->ctx)[cf->cycle->modules[i]->index]);

            } else if (cf->ctx) {
                confp = *(void **) ((char *) cf->ctx + cmd->conf);

                if (confp) {
                    conf = confp[cf->cycle->modules[i]->ctx_index];
                }
            }

            rv = cmd->set(cf, cmd, conf);

            if (rv == NGX_CONF_OK) {
                return NGX_OK;
            }

            if (rv == NGX_CONF_ERROR) {
                return NGX_ERROR;
            }

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "\"%s\" directive %s", name->data, rv);

            return NGX_ERROR;
        }
    }

    if (found) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "\"%s\" directive is not allowed here", name->data);

        return NGX_ERROR;
    }

    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                       "unknown directive \"%s\"", name->data);

    return NGX_ERROR;

invalid:

    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                       "invalid number of arguments in \"%s\" directive",
                       name->data);

    return NGX_ERROR;
}

2. 代码分析

这段代码是 Nginx 配置文件(如 nginx.conf)解析器的关键部分
每当 Nginx 读取到一个配置指令(directive)时(例如 worker_processesserverlisten 等),
就会调用此函数来:

  1. 查找该指令对应的处理函数(handler)
  2. 验证指令的使用上下文、参数数量、语法合法性
  3. 调用模块注册的 set 回调函数执行实际配置操作

1. 函数签名

static ngx_int_t
ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)

返回值NGX_OK 表示成功,NGX_ERROR 表示解析失败。
参数
cf:当前配置上下文(包含指令名、参数、模块信息等)。
last:表示当前指令的“结束状态”:
- NGX_OK:普通指令以 ; 结尾;
- NGX_CONF_BLOCK_START:以 { 开始的块(如 http { ... });
- 其他值表示非法结束。


2. 局部变量

{
    char           *rv;
    void           *conf, **confp;
    ngx_uint_t      i, found;
    ngx_str_t      *name;
    ngx_command_t  *cmd;
  • rvcmd->set 函数的返回值
  • conf:指向该指令应写入的配置结构体
  • confp:二级指针,用于访问复杂配置结构
  • i:模块遍历索引
  • found:标记是否找到名称匹配的指令(即使上下文不合法也算“found”)
  • name:当前要处理的指令名(cf->args->elts[0]
  • cmd:当前遍历到的命令结构

3. 获取指令名

    name = cf->args->elts;

4. 初始化 found 标志

    found = 0;

初始化为 0,若在模块中找到同名指令
即使上下文不对,也设为 1(用于区分“未知指令”和“指令位置错误”)。


5. 遍历所有已加载模块

    for (i = 0; cf->cycle->modules[i]; i++) {

cf->cycle->modules 是 Nginx 启动时加载的所有模块的数组,以 NULL 结尾。
依次检查每个模块是否定义了命令。


1. 跳过无命令的模块

        cmd = cf->cycle->modules[i]->commands;
        if (cmd == NULL) {
            continue;
        }

每个模块通过 commands 字段注册自己支持的指令(ngx_command_t 数组)。
若为 NULL,说明该模块不提供任何配置指令,跳过。


2. 遍历该模块的所有指令

        for ( /* void */ ; cmd->name.len; cmd++) {

ngx_command_t 数组以 name.len == 0 作为结束标志。
逐个检查指令名是否匹配。


1. 查找指令
            if (name->len != cmd->name.len) {
                continue;
            }

指令名长度比较(快速过滤)
长度不同,肯定不匹配,跳过(避免不必要的字符串比较)


指令名字符串比较

            if (ngx_strcmp(name->data, cmd->name.data) != 0) {
                continue;
            }

使用 ngx_strcmp(Nginx 的 strcmp 封装)比较指令名。
若不相等,跳过。

若相等,说明找到了同名指令


            found = 1;

标记已找到同名指令
即使后续因上下文不合法被跳过,也记录“此指令存在”,用于错误提示区分


2. 检查模块类型是否匹配当前上下文
            if (cf->cycle->modules[i]->type != NGX_CONF_MODULE
                && cf->cycle->modules[i]->type != cf->module_type)
            {
                continue;
            }

过滤掉在当前配置上下文中不该被处理的模块
确保只有与当前配置阶段(或上下文)类型匹配的模块才能参与指令解析

cf->module_type 表示当前配置块所属的模块类型(如 NGX_HTTP_MODULENGX_CORE_MODULE)。
模块必须是 NGX_CONF_MODULE(配置模块)或与当前上下文类型匹配,否则跳过。

例如:在 http {} 块中,cf->module_type == NGX_HTTP_MODULE,那么只有 HTTP 模块或 CONF 模块的指令才被接受。

NGX_CONF_MODULE:一个特殊的模块类型,
表示该模块是通用配置模块
可以在任何上下文中被调用


3. 检查指令位置
            /* is the directive's location right ? */

            if (!(cmd->type & cf->cmd_type)) {
                continue;
            }

cmd->type 是指令允许出现的上下文掩码,如 NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF
cf->cmd_type 是当前配置块的上下文(如 NGX_HTTP_SRV_CONF)。
cmd->type 不包含当前上下文,说明该指令不能在此处使用,跳过。

例如:listen 指令的 type 包含 NGX_HTTP_SRV_CONF,所以只能在 server {} 块中使用。


4. 检查非块指令是否以分号结束
            if (!(cmd->type & NGX_CONF_BLOCK) && last != NGX_OK) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                  "directive \"%s\" is not terminated by \";\"",
                                  name->data);
                return NGX_ERROR;
            }

如果指令不是块指令(即不应有 {}),
last != NGX_OK(说明不是以 ; 结尾),报错。


5. 检查块指令是否以花括号开始
            if ((cmd->type & NGX_CONF_BLOCK) && last != NGX_CONF_BLOCK_START) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "directive \"%s\" has no opening \"{\"",
                                   name->data);
                return NGX_ERROR;
            }

如果指令是块指令(如 httpserver),
last != NGX_CONF_BLOCK_START(说明没有 {),报错。


6. 验证参数数量是否合法
            /* is the directive's argument count right ? */

            if (!(cmd->type & NGX_CONF_ANY)) {

如果指令NGX_CONF_ANY(表示参数数量任意),则需严格检查参数个数。


处理布尔型指令(NGX_CONF_FLAG

                if (cmd->type & NGX_CONF_FLAG) {

                    if (cf->args->nelts != 2) {
                        goto invalid;
                    }

NGX_CONF_FLAG:指令必须有 1 个参数(加上指令名共 2 个词元),如 daemon on;
参数数量 ≠ 2,跳转到 invalid 标签报错。


处理“至少1个参数”指令(NGX_CONF_1MORE

                } else if (cmd->type & NGX_CONF_1MORE) {

                    if (cf->args->nelts < 2) {
                        goto invalid;
                    }

至少 1 个参数(总词元 ≥ 2),
常用于可变参数指令。


                } else if (cmd->type & NGX_CONF_2MORE) {

                    if (cf->args->nelts < 3) {
                        goto invalid;
                    }

处理“至少2个参数”指令(NGX_CONF_2MORE
至少 2 个参数(总词元 ≥ 3)


检查参数总数是否超过最大限制


                } else if (cf->args->nelts > NGX_CONF_MAX_ARGS) {

                    goto invalid;

Nginx 默认最多支持 8个参数。
超过则报错。


检查固定参数数量(通过位掩码)

                } else if (!(cmd->type & argument_number[cf->args->nelts - 1]))
                {
                    goto invalid;
                }
            }
  • argument_number[] 是一个预定义数组,例如:
    static ngx_uint_t argument_number[] = {
        NGX_CONF_NOARGS,   // 0 参数(仅指令名)
        NGX_CONF_TAKE1,    // 1 参数
        NGX_CONF_TAKE2,    // 2 参数
        NGX_CONF_TAKE3,
        NGX_CONF_TAKE4,
        NGX_CONF_TAKE5,
        NGX_CONF_TAKE6,
        NGX_CONF_TAKE7
    };
    
  • cf->args->nelts - 1 是实际参数个数(去掉指令名)。
  • 检查 cmd->type 是否包含对应的 NGX_CONF_TAKEn 位。
  • 若不包含,说明参数数量不匹配,报错。

例如:worker_processesNGX_CONF_TAKE1,如果写成 worker_processes 2 3;(2 个参数),就会失败。


7. 确定配置结构体的写入位置(conf)
            /* set up the directive's configuration context */

            conf = NULL;

初始化 confNULL,后续根据指令类型赋值。


情况1:NGX_DIRECT_CONF —— 直接使用模块上下文
            if (cmd->type & NGX_DIRECT_CONF) {
                conf = ((void **) cf->ctx)[cf->cycle->modules[i]->index];

用于核心模块(如 NGX_CORE_MODULE),配置直接存在 cf->ctx 数组中。
cf->ctx 是一个 void**,每个模块占一个 slot。
直接取第 index 个元素作为配置结构体指针。


情况2:NGX_MAIN_CONF —— 主配置(取地址)
            } else if (cmd->type & NGX_MAIN_CONF) {
                conf = &(((void **) cf->ctx)[cf->cycle->modules[i]->index]);

注意这里是 &(...),取的是指针的地址
用于需要修改指针本身的情况(如动态分配配置结构)。


情况3:普通配置
            } else if (cf->ctx) {
                confp = *(void **) ((char *) cf->ctx + cmd->conf);

                if (confp) {
                    conf = confp[cf->cycle->modules[i]->ctx_index];
                }
            }
  • cf->ctx 指向当前配置上下文(如 ngx_http_conf_ctx_t)。
  • cmd->conf 是一个偏移量(offsetof),指向该模块在上下文中的配置指针数组。
  • confp 是一个 void*[],存储 main/srv/loc 三级配置。
  • ctx_index 是该模块在其类型(如 HTTP 模块)中的索引。
  • 最终 conf 指向具体的配置结构体(如 ngx_http_core_srv_conf_t)。

对于HTTP模块,cf->ctx 所指向的结构体中有 3 个字段(3 个指向数组的指针),
cmd->conf 是某个字段相对于这个结构体的偏移量,
cf->ctx + cmd->conf 指向结构体其中一个字段(一个指针,指向一个指针数组) confp
ctx_index 是该模块在 confp 数组中的索引
所得conf 指向具体的配置结构体

这是 Nginx 多级配置继承机制的核心。


8. 调用指令的 set 函数(真正处理配置)
            rv = cmd->set(cf, cmd, conf);
  • cmd->set 是模块注册的回调函数,负责解析参数并写入 conf
  • 返回值:
    • NGX_CONF_OK:成功;
    • NGX_CONF_ERROR:失败;
    • 其他:错误字符串(如 "invalid value")。

9. 处理 set 函数的返回值
            if (rv == NGX_CONF_OK) {
                return NGX_OK;
            }

            if (rv == NGX_CONF_ERROR) {
                return NGX_ERROR;
            }
  • 成功则返回 NGX_OK
  • 明确错误返回 NGX_ERROR

处理自定义错误信息

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "\"%s\" directive %s", name->data, rv);

            return NGX_ERROR;
        }
    }

如果 rv 是字符串(如 "port is invalid"),
打印 "listen directive port is invalid"
返回错误。


6. 指令名存在,但上下文不合法

    if (found) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "\"%s\" directive is not allowed here", name->data);

        return NGX_ERROR;
    }
  • 说明指令名存在,但在当前配置块中不允许使用

7. 完全未知的指令

    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                       "unknown directive \"%s\"", name->data);

    return NGX_ERROR;

没有任何模块注册该指令名,属于拼写错误或无效指令


8. 参数数量错误的统一处理(invalid 标签)

invalid:

    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                       "invalid number of arguments in \"%s\" directive",
                       name->data);

    return NGX_ERROR;
}

跳转至此处,说明参数数量不符合要求。


9. 总结:

ngx_conf_handler 的核心作用

  1. 指令路由:根据指令名找到对应的模块和 ngx_command_t
  2. 上下文校验:确保指令用在允许的配置块中(如 httpserver)。
  3. 语法校验
    • 块指令必须有 {
    • 普通指令必须有 ;
    • 参数数量必须合法。
  4. 配置定位:确定该指令的值应写入哪个配置结构体(main/srv/loc)。
  5. 调用处理函数:执行模块注册的 set 函数完成实际配置。
  6. 错误反馈:提供清晰的错误信息(未知指令、位置错误、参数错误等)。

这是 Nginx 高度模块化、可扩展配置系统的核心实现,也是其配置语法强大而严谨的基础。


3. ngx_conf_handler 函数逻辑流程

一、函数入口与初始化

1.1 输入参数

  • ngx_conf_t *cf:当前配置上下文
    • 包含:当前指令参数(cf->args)、模块类型(cf->module_type)、配置上下文(cf->ctx)、命令类型(cf->cmd_type)等
  • ngx_int_t last:当前指令的结束状态
    • NGX_OK → 以 ; 结尾(普通指令)
    • NGX_CONF_BLOCK_START → 以 { 开始(块指令)
    • 其他值 → 语法错误

1.2 局部变量初始化

  • name = cf->args->elts:取指令名(args[0]
  • found = 0:标记是否找到同名指令(用于区分“未知指令” vs “位置错误”)

二、遍历所有已加载模块

2.1 外层循环:for (i = 0; cf->cycle->modules[i]; i++)

  • 遍历 cf->cycle->modules[] 数组(以 NULL 结尾)

2.2 跳过无指令的模块

  • modules[i]->commands == NULLcontinue

三、遍历当前模块的所有指令(ngx_command_t 数组)

3.1 内层循环:for (; cmd->name.len; cmd++)

  • cmd->name.len == 0 作为终止条件

3.2 指令名匹配检查

3.2.1 长度快速过滤
  • name->len != cmd->name.lencontinue
3.2.2 字符串精确匹配
  • ngx_strcmp(name->data, cmd->name.data) != 0continue
3.2.3 匹配成功 → 标记 found = 1
  • 表示“该指令名存在”,即使后续因上下文被拒,也记录此状态

四、模块类型合法性检查

4.1 条件判断

if (module->type != NGX_CONF_MODULE && module->type != cf->module_type)

4.2 逻辑含义

  • 仅以下两类模块可参与处理:
    • 通用配置模块type == NGX_CONF_MODULE
    • 当前上下文匹配模块type == cf->module_type
      • 例如:在 http {} 块中,cf->module_type == NGX_HTTP_MODULE

4.3 不匹配 → continue(跳过该指令)


五、指令上下文(作用域)合法性检查

5.1 位掩码匹配

  • 检查:(cmd->type & cf->cmd_type) != 0
    • cmd->type:指令允许出现的上下文(如 NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF
    • cf->cmd_type:当前配置块的上下文类型(如 NGX_HTTP_SRV_CONF

5.2 不匹配 → continue(指令不允许在此处使用)


六、指令语法合法性检查

6.1 块指令 vs 普通指令结束符检查

6.1.1 普通指令(非 NGX_CONF_BLOCK
  • 要求:last == NGX_OK(即以 ; 结尾)
  • 否则报错:"directive \"X\" is not terminated by \";\""
6.1.2 块指令(cmd->type & NGX_CONF_BLOCK
  • 要求:last == NGX_CONF_BLOCK_START(即后跟 {
  • 否则报错:"directive \"X\" has no opening \"{\""

6.2 参数数量合法性检查(若非 NGX_CONF_ANY

6.2.1 NGX_CONF_FLAG
  • 要求:cf->args->nelts == 2(指令名 + 1 个参数,如 on/off
6.2.2 NGX_CONF_1MORE
  • 要求:cf->args->nelts >= 2(至少 1 个参数)
6.2.3 NGX_CONF_2MORE
  • 要求:cf->args->nelts >= 3(至少 2 个参数)
6.2.4 固定参数数量(NGX_CONF_TAKE1 ~ TAKE7
  • 通过 argument_number[cf->args->nelts - 1] 位掩码匹配
  • 例如:TAKE2 要求 nelts == 3
6.2.5 参数总数上限
  • cf->args->nelts > NGX_CONF_MAX_ARGS(通常为 5)→ 报错
6.2.6 任意参数(NGX_CONF_ANY
  • 跳过所有参数检查(极少见)

6.3 参数错误统一处理

  • 跳转到 invalid: 标签
  • 报错:"invalid number of arguments in \"X\" directive"

七、确定配置写入位置(conf 指针定位)

7.1 NGX_DIRECT_CONF 类型

  • conf = ((void **)cf->ctx)[module->index]
  • 用于核心模块,直接使用 cf->ctx 中的配置结构体

7.2 NGX_MAIN_CONF 类型

  • conf = &(((void **)cf->ctx)[module->index])
  • 取配置指针的地址(较少使用)

7.3 普通模块(HTTP/Stream 等)

  • 通过偏移量 cmd->conf 定位到配置指针数组
  • confp = *(void **)((char *)cf->ctx + cmd->conf)
  • conf = confp[module->ctx_index]
  • 支持 main/srv/loc 三级配置继承

八、调用指令处理函数 cmd->set

8.1 调用

  • rv = cmd->set(cf, cmd, conf)

8.2 处理返回值

8.2.1 rv == NGX_CONF_OK
  • 成功 → return NGX_OK
8.2.2 rv == NGX_CONF_ERROR
  • 失败 → return NGX_ERROR
8.2.3 rv == char*(错误字符串)
  • 报错:"\"X\" directive Y"(Y 为错误描述)
  • return NGX_ERROR

九、遍历结束后的兜底错误处理

9.1 所有模块遍历完毕,未找到合法处理路径

9.2 判断错误类型

9.2.1 found == 1
  • 指令名存在,但上下文/模块类型/作用域不匹配
  • 报错:"\"X\" directive is not allowed here"
9.2.2 found == 0
  • 完全未知的指令
  • 报错:"unknown directive \"X\""

9.3 统一返回 NGX_ERROR


十、函数出口

  • 唯一成功路径cmd->set 返回 NGX_CONF_OKreturn NGX_OK
  • 所有其他路径return NGX_ERROR

总结:四重过滤 + 一层执行

  1. 名称过滤 → 是我认识的指令吗?
  2. 模块过滤 → 当前上下文允许这个模块参与吗?
  3. 作用域过滤 → 这个指令能在这里用吗?
  4. 语法过滤 → 参数、分号、花括号对吗?
  5. 执行层 → 调用 set 函数真正配置

这种层层递进、严格校验的设计,使 Nginx 配置系统兼具 灵活性、安全性与可扩展性


ngx_conf_handler(cf, last)
│
├── 📥 输入参数
│   ├── cf: ngx_conf_t*
│   │   ├── cf->args         → 当前指令词元数组(含指令名 + 参数)
│   │   ├── cf->module_type  → 当前模块上下文类型(如 NGX_HTTP_MODULE)
│   │   ├── cf->cmd_type     → 当前配置块允许的指令类型位掩码
│   │   └── cf->ctx          → 配置上下文指针(如 http_conf_ctx)
│   └── last: ngx_int_t
│       ├── NGX_OK                 → 指令以 ";" 结尾
│       ├── NGX_CONF_BLOCK_START   → 指令后跟 "{"
│       └── 其他值                 → 语法错误
│
├── 🧹 初始化
│   ├── name = cf->args[0]         → 提取指令名(ngx_str_t*)
│   └── found = 0                  → 标记是否找到同名指令
│
├── 🔁 遍历所有模块 (for i in modules)
│   ├── 跳过 commands == NULL 的模块
│   │
│   └── 🔁 遍历模块的每条指令 (for cmd in module->commands)
│       ├── 🔍 指令名匹配?
│       │   ├── 长度不同? → continue
│       │   ├── 字符串不同? → continue
│       │   └── ✅ 匹配 → found = 1
│       │
│       ├── 🧩 模块类型合法?
│       │   └── if (type != NGX_CONF_MODULE && type != cf->module_type)
│       │       └── ❌ 不合法 → continue
│       │
│       ├── 📍 指令上下文合法?(作用域检查)
│       │   └── if (!(cmd->type & cf->cmd_type))
│       │       └── ❌ 不允许在此处使用 → continue
│       │
│       ├── 🔤 语法合法性检查
│       │   ├── 🧱 块指令 vs 普通指令
│       │   │   ├── 非块指令 + last != NGX_OK → ❌ 缺分号
│       │   │   └── 块指令 + last != NGX_CONF_BLOCK_START → ❌ 缺 "{"
│       │   │
│       │   └── 📏 参数数量检查(若非 NGX_CONF_ANY)
│       │       ├── NGX_CONF_FLAG      → 必须 2 个词元(指令+1参)
│       │       ├── NGX_CONF_1MORE     → ≥2 词元
│       │       ├── NGX_CONF_2MORE     → ≥3 词元
│       │       ├── NGX_CONF_TAKE1~5   → 严格匹配(通过 argument_number[] 位掩码)
│       │       ├── 超过 NGX_CONF_MAX_ARGS(通常5)→ ❌
│       │       └── 不匹配 → goto invalid
│       │
│       ├── 🎯 定位配置结构体 (conf)
│       │   ├── NGX_DIRECT_CONF → conf = cf->ctx[module->index]
│       │   ├── NGX_MAIN_CONF   → conf = &cf->ctx[module->index]
│       │   └── 普通模块(HTTP/Stream)
│       │       └── conf = ((cf->ctx + cmd->conf))[module->ctx_index]
│       │
│       └── ⚙️ 调用 cmd->set(cf, cmd, conf)
│           ├── 返回 NGX_CONF_OK → ✅ return NGX_OK
│           ├── 返回 NGX_CONF_ERROR → ❌ return NGX_ERROR
│           └── 返回 char*(错误串)→ log +return NGX_ERROR
│
├── 🚨 遍历结束,未成功处理
│   ├── if (found == 1)
│   │   └── 💥 "directive 'X' is not allowed here"
│   └── else
│       └── ❓ "unknown directive 'X'"
│
└── 🛑 统一返回 NGX_ERROR(除成功路径外)
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐