目录

 

0.Nginx中的配置需要思考的问题

1.Nginx中的配置的嵌套结构

2.指令的上下文,分类和合并

3.值指令继承规则

4.HTTP模块合并配置的实现


0.Nginx中的配置需要思考的问题

Nginx的配置中需要考虑的问题:
(1)当一个指令出现在多个配置快中,到底以谁为准呢?
(2)在有些配置块下,没有这条指令,我们在使用的时候却把它配置上了而且生效了,这又是为什么呢?
(3)还有一些第三方模块不支持官方模块的一些规则,这时我们该如何判断配置指令到底是怎样生效,以谁为准呢?

 

1.Nginx中的配置的嵌套结构

 

nginx access_log 大小设置 nginx access配置_#if

main--事件模块,配置进程,user,上下文等,都是在main中的;
http{
       upstream{}
       split_client{}
       map{}
       geo{}
       server{
               location{}
             }
}
http-server-location是http服务的框架所定义的核心模块,处理请求的时候要先按照请求中请求的域名
(比如host找到相应的server块,然后更加url找到location,然后根据location下面的具体指令来处理
请求),在这样一个典型的嵌套配置中,我们可以发现很多冲突或者奇怪的指令.

2.指令的上下文,分类和合并

 

nginx access_log 大小设置 nginx access配置_HTTP_02

context:中文翻译“上下文”

上图示例一可以看到log_format这个指令的上下文是http,所以如果将log_format指令配置到
server或者location中时,Nginx检测配置文件是会报错的,不能生效.

上图示例二中可以看到access_log可以出现的上下文包括http,server,location...
当指令在多个模块下同时存在的时候,它可能是可以合并的,但也可能是不可以合并的.


指令分类:
(1)值指令--对这个指令下存储当时配置的值;
(2)动作类指令;


值指令:不同块下可以合并,如root,access_log,gzip;
动作类指令:指定行为,不可以合并,如rewrite,proxy_pass...

如何判断一个指令可以合并还是不可以合并呢?
server_write和rewrite只有我们的http_rewrite模块才可能去提供,content模块一般是
反向代理或者是其他模块中的content,这些content模块通常提供的一些方法只能是动作
类的指令.这些一般是不可以合并的.当然我们也可以通过源码可以判断出来这个支线是什
么类型的指令.相对来说,动作类的指令不是很多.

3.值指令继承规则

存储值的指令继承规则:向上覆盖.
(1)子配置不存在时,直接使用父配置块;
(2)子配置存在时,直接覆盖父配置块.
如【1.Nginx中的配置的嵌套结构】中的图配置中的
(1)倒数第三行的location中没有配置root,则使用父配置server中配置的root;
(2)第七行的access_log在父配置server中的第四行也配置过了,会覆盖掉父配置中的这个配置块.

server {
	listen	8080;  # listen只能出现在server这个上下文中
	root /home/geek/nginx/html;
	access_log logs/geek.access.log main;
	location /test {
		root /home/geek/nginx/test;  # 覆盖父配置
		access_log logs/access.test.log main;  # 覆盖父配置
	}
	location /dlib {
		alias dlib/;
	}
	location / {  # 使用父配置块的root和access_log的配置
	}
}

4.HTTP模块合并配置的实现

所有Nginx官方模块都符合上面所说的值指令的规则,但一些第三方模块可能并没有遵循这个规则.
如果此时的说明文档也不是很详细的话,就需要我们通过源码来判断.
如何通过源码来看值指令的配置情况:
(1)指令在哪个块下生效(有些指令是在server下生效的,但大部分指令都是在location下生效的);
(2)指令允许出现在哪些块下(如access_log可以出现在if,server,location等很多块下);
(3)在server块生效时,会定义出merger_srv_conf这个方法,指令出现在http和server两处,从http向
server合并指令;
   如果是在location生效,会定义merger_loc_conf这个方法.
(4)配置缓存在内存.


代码版本1.13.7
如ngx_http_referer_module这个模块:

static ngx_command_t  ngx_http_referer_commands[] = {

    { ngx_string("valid_referers"),
      NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
     //NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF表示可以出现在HTTP_SRV和HTTP_LOC模块,NGX_CONF_1MORE表示可以有一个参数或多个参数
      ngx_http_valid_referers,
      NGX_HTTP_LOC_CONF_OFFSET,
      0,
      NULL },

    { ngx_string("referer_hash_max_size"),
      NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_num_slot,
      NGX_HTTP_LOC_CONF_OFFSET,
      offsetof(ngx_http_referer_conf_t, referer_hash_max_size),
      NULL },

    { ngx_string("referer_hash_bucket_size"),
      NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_num_slot,
      NGX_HTTP_LOC_CONF_OFFSET,
      offsetof(ngx_http_referer_conf_t, referer_hash_bucket_size),
      NULL },

      ngx_null_command
};

static ngx_http_module_t  ngx_http_referer_module_ctx = {
    ngx_http_referer_add_variables,        /* preconfiguration */
    NULL,                                  /* postconfiguration */

    NULL,                                  /* create main configuration */
    NULL,                                  /* init main configuration */

    NULL,                                  /* create server configuration */
    NULL,                                  /* merge server configuration */

    ngx_http_referer_create_conf,          /* create location configuration */
    ngx_http_referer_merge_conf            /* merge location configuration */
};


ngx_module_t  ngx_http_referer_module = {
    NGX_MODULE_V1,
    &ngx_http_referer_module_ctx,          /* module context */
    ngx_http_referer_commands,             /* module directives */
    NGX_HTTP_MODULE,                       /* module type */
    NULL,                                  /* init master */
    NULL,                                  /* init module */
    NULL,                                  /* init process */
    NULL,                                  /* init thread */
    NULL,                                  /* exit thread */
    NULL,                                  /* exit process */
    NULL,                                  /* exit master */
    NGX_MODULE_V1_PADDING
};

// 创建配置文件
static void *
ngx_http_referer_create_conf(ngx_conf_t *cf)
{
    ngx_http_referer_conf_t  *conf;

    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_referer_conf_t));
    if (conf == NULL) {
        return NULL;
    }

    /*
     * set by ngx_pcalloc():
     *
     *     conf->hash = { NULL };
     *     conf->server_names = 0;
     *     conf->keys = NULL;
     */

#if (NGX_PCRE)
    conf->regex = NGX_CONF_UNSET_PTR;
    conf->server_name_regex = NGX_CONF_UNSET_PTR;
#endif

    conf->no_referer = NGX_CONF_UNSET;
    conf->blocked_referer = NGX_CONF_UNSET;
    conf->referer_hash_max_size = NGX_CONF_UNSET_UINT;
    conf->referer_hash_bucket_size = NGX_CONF_UNSET_UINT;

    return conf;
}


// 指令合并,这个函数里就定义了这个模块的配置的合并方法,每个模块的合并方法源码可以清晰给出
static char *
ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, void *child)
{
    ngx_http_referer_conf_t *prev = parent;
    ngx_http_referer_conf_t *conf = child;

    ngx_uint_t                 n;
    ngx_hash_init_t            hash;
    ngx_http_server_name_t    *sn;
    ngx_http_core_srv_conf_t  *cscf;

    if (conf->keys == NULL) {
        conf->hash = prev->hash;

#if (NGX_PCRE)
        ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL);
        ngx_conf_merge_ptr_value(conf->server_name_regex,
                                 prev->server_name_regex, NULL);
#endif
        ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0);
        ngx_conf_merge_value(conf->blocked_referer, prev->blocked_referer, 0);
        ngx_conf_merge_uint_value(conf->referer_hash_max_size,
                                  prev->referer_hash_max_size, 2048);
        ngx_conf_merge_uint_value(conf->referer_hash_bucket_size,
                                  prev->referer_hash_bucket_size, 64);

        return NGX_CONF_OK;
    }

    if (conf->server_names == 1) {
        cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module);

        sn = cscf->server_names.elts;
        for (n = 0; n < cscf->server_names.nelts; n++) {

#if (NGX_PCRE)
            if (sn[n].regex) {

                if (ngx_http_add_regex_server_name(cf, conf, sn[n].regex)
                    != NGX_OK)
                {
                    return NGX_CONF_ERROR;
                }

                continue;
            }
#endif

            if (ngx_http_add_referer(cf, conf->keys, &sn[n].name, NULL)
                != NGX_OK)
            {
                return NGX_CONF_ERROR;
            }
        }
    }

    if ((conf->no_referer == 1 || conf->blocked_referer == 1)
        && conf->keys->keys.nelts == 0
        && conf->keys->dns_wc_head.nelts == 0
        && conf->keys->dns_wc_tail.nelts == 0)
    {
        ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                      "the \"none\" or \"blocked\" referers are specified "
                      "in the \"valid_referers\" directive "
                      "without any valid referer");
        return NGX_CONF_ERROR;
    }

    ngx_conf_merge_uint_value(conf->referer_hash_max_size,
                              prev->referer_hash_max_size, 2048);
    ngx_conf_merge_uint_value(conf->referer_hash_bucket_size,
                              prev->referer_hash_bucket_size, 64);
    conf->referer_hash_bucket_size = ngx_align(conf->referer_hash_bucket_size,
                                               ngx_cacheline_size);

    hash.key = ngx_hash_key_lc;
    hash.max_size = conf->referer_hash_max_size;
    hash.bucket_size = conf->referer_hash_bucket_size;
    hash.name = "referer_hash";
    hash.pool = cf->pool;

    if (conf->keys->keys.nelts) {
        hash.hash = &conf->hash.hash;
        hash.temp_pool = NULL;

        if (ngx_hash_init(&hash, conf->keys->keys.elts, conf->keys->keys.nelts)
            != NGX_OK)
        {
            return NGX_CONF_ERROR;
        }
    }

    if (conf->keys->dns_wc_head.nelts) {

        ngx_qsort(conf->keys->dns_wc_head.elts,
                  (size_t) conf->keys->dns_wc_head.nelts,
                  sizeof(ngx_hash_key_t),
                  ngx_http_cmp_referer_wildcards);

        hash.hash = NULL;
        hash.temp_pool = cf->temp_pool;

        if (ngx_hash_wildcard_init(&hash, conf->keys->dns_wc_head.elts,
                                   conf->keys->dns_wc_head.nelts)
            != NGX_OK)
        {
            return NGX_CONF_ERROR;
        }

        conf->hash.wc_head = (ngx_hash_wildcard_t *) hash.hash;
    }

    if (conf->keys->dns_wc_tail.nelts) {

        ngx_qsort(conf->keys->dns_wc_tail.elts,
                  (size_t) conf->keys->dns_wc_tail.nelts,
                  sizeof(ngx_hash_key_t),
                  ngx_http_cmp_referer_wildcards);

        hash.hash = NULL;
        hash.temp_pool = cf->temp_pool;

        if (ngx_hash_wildcard_init(&hash, conf->keys->dns_wc_tail.elts,
                                   conf->keys->dns_wc_tail.nelts)
            != NGX_OK)
        {
            return NGX_CONF_ERROR;
        }

        conf->hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash;
    }

#if (NGX_PCRE)
    ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL);
    ngx_conf_merge_ptr_value(conf->server_name_regex, prev->server_name_regex,
                             NULL);
#endif

    if (conf->no_referer == NGX_CONF_UNSET) {
        conf->no_referer = 0;
    }

    if (conf->blocked_referer == NGX_CONF_UNSET) {
        conf->blocked_referer = 0;
    }

    conf->keys = NULL;

    return NGX_CONF_OK;
}