nginx 的多个参数解析

本文详细介绍了Nginx中server_name指令的工作原理及其实现细节,包括如何支持多个参数值、参数的有效性检查、正则表达式匹配等。

       由于笔者需要,开发nginx模块,有一个配置命令需要传入多个值,然而在网上找了又找,都是传递一个参数的,于是乎,没有办法只能在源码中徜徉了,找到了,类似命令就

是server块中的server_name命令,允许有多个值的存在,现在看下nginx自己是怎么进行解析的吧,由于我们只需要在本模块中使用命令,也就是说,我们只需要解析就好,不需

要跟全局命令进行merge了,好了,不多说,开始吧

nginx.conf中的内容是这样的

server {
        listen       80;
        server_name  localhost  alias;
... 
       }
server_name可以有超过一个参数的值

该命令项是:

{ ngx_string("server_name"),
      NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
      ngx_http_core_server_name,
      NGX_HTTP_SRV_CONF_OFFSET,
      0,
      NULL 
}
指明了该值是在SERVER块中定义的 NGX_HTTP_SRV_CONF,允许有超过一个参数 NGX_CONF_1MORE,解析函数是ngx_http_core_server_name,该函数定义是这样的

static char *
ngx_http_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_core_srv_conf_t *cscf = conf;//ngx_http_core_srv_conf_t定义在当前文件中

    u_char                   ch;
    ngx_str_t               *value;
    ngx_uint_t               i;
    ngx_http_server_name_t  *sn;

    value = cf->args->elts;

    for (i = 1; i < cf->args->nelts; i++) {

        ch = value[i].data[0];

        if ((ch == '*' && (value[i].len < 3 || value[i].data[1] != '.'))
            || (ch == '.' && value[i].len < 2))
        {
            //如果server_name的值是以*开始,并且(长度小于3的字符串,或者字符串第二个字符不是.的)不可用
            //或者第一个字符是.并且长度小于2,也是不可用的
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "server name \"%V\" is invalid", &value[i]);
            return NGX_CONF_ERROR;
        }

        if (ngx_strchr(value[i].data, '/')) {
            //如果server_name中有/字符的也不可用
            ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
                               "server name \"%V\" has suspicious symbols",
                               &value[i]);
        }
        //否则,在cscf中新建一个数组元素,并且返回新元素指针,
        sn = ngx_array_push(&cscf->server_names);
        if (sn == NULL) {
            return NGX_CONF_ERROR;
        }
        //接下来是给新元素指针sn赋值
#if (NGX_PCRE)
        sn->regex = NULL;
#endif
        sn->server = cscf;
        //
        if (ngx_strcasecmp(value[i].data, (u_char *) "$hostname") == 0) {
            sn->name = cf->cycle->hostname;

        } else {
            //给新元素的服务器名称赋值
            sn->name = value[i];
        }

        if (value[i].data[0] != '~') {
            //服务器名称都是小写的
            ngx_strlow(sn->name.data, sn->name.data, sn->name.len);
            continue;
        }

#if (NGX_PCRE)  //这里面应该就是正则表达式部分,不予置评
        
        {
        u_char               *p;
        ngx_regex_compile_t   rc;
        u_char                errstr[NGX_MAX_CONF_ERRSTR];

        if (value[i].len == 1) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "empty regex in server name \"%V\"", &value[i]);
            return NGX_CONF_ERROR;
        }

        value[i].len--;
        value[i].data++;

        ngx_memzero(&rc, sizeof(ngx_regex_compile_t));

        rc.pattern = value[i];
        rc.err.len = NGX_MAX_CONF_ERRSTR;
        rc.err.data = errstr;

        for (p = value[i].data; p < value[i].data + value[i].len; p++) {
            if (*p >= 'A' && *p <= 'Z') {
                rc.options = NGX_REGEX_CASELESS;
                break;
            }
        }

        sn->regex = ngx_http_regex_compile(cf, &rc);
        if (sn->regex == NULL) {
            return NGX_CONF_ERROR;
        }

        sn->name = value[i];
        cscf->captures = (rc.captures > 0);
        }
#else
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "using regex \"%V\" "
                           "requires PCRE library", &value[i]);

        return NGX_CONF_ERROR;
#endif
    }

    return NGX_CONF_OK;
}

除此之外,之前我们还应该建立存放命令的结构体的变量内存,该开辟过程,放在了ngx_http_core_create_srv_conf中

static void *ngx_http_core_create_srv_conf(ngx_conf_t *cf);

该函数的调用就是在建立SERVER解析的时候

static ngx_http_module_t  ngx_http_core_module_ctx = {
    ngx_http_core_preconfiguration,        /* preconfiguration */
    NULL,                                  /* postconfiguration */

    ngx_http_core_create_main_conf,        /* create main configuration */
    ngx_http_core_init_main_conf,          /* init main configuration */

    ngx_http_core_create_srv_conf,         /* create server configuration */
    ngx_http_core_merge_srv_conf,          /* merge server configuration */

    ngx_http_core_create_loc_conf,         /* create location configuration */
    ngx_http_core_merge_loc_conf           /* merge location configuration */
};
这样,在该模块中,我们就能够使用传递进来的变量了

### 如何管理和使用 Nginx 多个配置文件的最佳实践 #### 使用 include 指令管理多个配置文件 为了更好地组织和维护 Nginx 的配置,可以利用 `include` 指令来加载额外的配置文件。这使得主配置文件保持简洁,并允许按功能或站点划分配置[^1]。 ```nginx http { ... include /etc/nginx/conf.d/*.conf; } ``` 上述代码会引入 `/etc/nginx/conf.d/` 目录下所有的 `.conf` 文件作为附加配置的一部分。 #### 组织结构建议 创建合理的目录结构有助于提高可读性和便于后续扩展: - **全局设置**:放置于主配置文件中 (`nginx.conf`)。 - **虚拟主机配置**:各自独立保存在一个单独的文件内 (如 `/etc/nginx/sites-available/example.com`) 并通过符号链接激活到 `sites-enabled` 中。 - **特定模块或服务配置**:存放在专门的子目录里 (比如 `/etc/nginx/modules-available/`, `/etc/nginx/snippets/`)。 这种做法不仅使每个部分更加专注其职责范围内的事情,而且方便团队协作开发与部署操作[^3]. #### 动态调整工作进程数 对于多核 CPU 或者高并发场景下的服务器而言,在不同的配置文件中合理设定 worker_processes 参数是非常重要的。通常情况下可以根据CPU核心数量自动计算最优值: ```bash worker_processes auto; ``` 此行应位于 main context 下方, 即不在任何 server 或 http block 内部定义. #### 测试新配置的有效性 每当编辑完新的配置文件之后都应该执行测试命令确保语法无误并能正常解析: ```bash nginx -t ``` 如果一切顺利,则可以通过发送信号给正在运行的服务实例使其重新加载最新的更改而无需重启整个应用;反之则需修正错误后再试一次: ```bash nginx -s reload ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

世纪殇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值