目录
0.Nginx中的配置需要思考的问题
1.Nginx中的配置的嵌套结构
2.指令的上下文,分类和合并
3.值指令继承规则
4.HTTP模块合并配置的实现
0.Nginx中的配置需要思考的问题
Nginx的配置中需要考虑的问题:
(1)当一个指令出现在多个配置快中,到底以谁为准呢?
(2)在有些配置块下,没有这条指令,我们在使用的时候却把它配置上了而且生效了,这又是为什么呢?
(3)还有一些第三方模块不支持官方模块的一些规则,这时我们该如何判断配置指令到底是怎样生效,以谁为准呢?
1.Nginx中的配置的嵌套结构
main--事件模块,配置进程,user,上下文等,都是在main中的;
http{
upstream{}
split_client{}
map{}
geo{}
server{
location{}
}
}
http-server-location是http服务的框架所定义的核心模块,处理请求的时候要先按照请求中请求的域名
(比如host找到相应的server块,然后更加url找到location,然后根据location下面的具体指令来处理
请求),在这样一个典型的嵌套配置中,我们可以发现很多冲突或者奇怪的指令.
2.指令的上下文,分类和合并
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;
}