1. 配置介绍
nginx的配置由一个主配置文件和其他一些辅助的配置文件构成。这些配置文件均是纯文本文件,这些配置文件全部位于nginx安装目录下的conf目录中。
主配置文件nginx.conf中的内容大概是这样子的:
#user nobody;
worker_processes 1;
pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
从上面可以看出:nginx.conf由若干配置项组成,配置项又分为简单配置项和块配置项。
简单配置项由配置项名和配置项值构成。
配置项名是一个字符串,可以用单引号或者双引号括起来,也可以不扩。但是如果配置项名包含空格,则一定要括起来。配置项值使用一个或者多个空格或者TAB与配置项名分开,配置项值可以是数字或者字符串(当然也包括正则表达式)。一个配置项可以有多个配置项值,多个配置项值之间也由空格或者TAB分隔。简单配置项的结尾使用分号结束,其基本的语法格式如下:
配置项名 配置项值1 配置项值2 ... ;
块配置项由一个配置项名和一对大括号组成,其结尾不需要再添加分号。块配置项使用大括号把一系列所属的配置项全部包含起来,表示大括号内的配置项同时生效;块配置项也可以有配置项值,这取决于解析这个配置项的模块;块配置项可以嵌套,内层块直接继承外层块,同一个配置项可以同时出现在内外层块配置项中,其优先级也取决于解析该配置项的模块。
2. 配置解析流程
nginx配置解析的流程基本上是一个递归的过程,如下图所示:
在配置解析的入口函数 ngx_conf_parse 中会循环读取配置文件中的内容,每读取一行后就解析该配置项。解析的过程中可能会再次调用该函数完成后续配置项的解析,例如events块配置项,http块配置项的解析。
对应的源码:
char * ngx_conf_parse(ngx_conf_t * cf, ngx_str_t * filename)
{
...
if( filename ){
fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
...
} else if(cf->conf_file->file.fd != NGX_INVALID_FILE){
type = parse_block;
} else {
type = parse_param;
}
for( ;; ){
rc = ngx_conf_read_token(cf);
if(cf->handler){
...
}
rc = ngx_conf_handler(cf, rc);
}
...
}
static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)
{
for(i = 0; cf->cycle->modules[i]; i++){
cmd = cf->cycle->modules[i]->commands;
if(cmd == NULL){
continue;
}
for( ; cmd->name.len; cmd++ ){
if( name->len != cmd->name.len){
continue;
}
if(ngx_strcmp(name->data, cmd->name.data) != 0){
continue;
}
found = 1;
...
rc = cmd->set(cf, cmd, conf);
}
}
}
ngx_conf_parse函数支持三种不同的解析环境:
- parse_file:解析配置文件
- parse_block: 解析块配置项
- parse_param:解析命令行配置。(注:命令行配置不支持块配置项)
从前面的解析流程可以看出,首次调用ngx_conf_parse进行配置解析时,类型为parse_file,当递归调用时,ngx_conf_parse的filename参数均设置为空,即正在进行块配置项的解析,例如:
static char * ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
...
cf->ctx = ctx;
cf->module_type = NGX_EVENT_MODULE;
cf->cmd_type = NGX_EVENT_CONF;
rv = ngx_conf_parse(cf, NULL);
...
}
在ngx_conf_handler的校验过程中会针对模块类型、配置项类型、配置项值个数等进行校验。
- 模块类型:校验配置项所属的模块是否为当前处理配置项解析的模块。
if( cf->cycle->modules[i]->type != NGX_CONF_MODULE &&
cf->cycle->modules[i]->type != cf->module_type ){
continue;
}
cf->module_type 初始值设置为 NGX_CORE_MODULE(在ngx_init_cycle函数中初始化),解析到配置项 http { 的时候,找到ngx_http_module模块,并调用ngx_http_block处理该配置项。从ngx_http_module模块的定义可以看到其类型确实为NGX_CORE_MODULE。
static ngx_command_t ngx_http_commands[] = {
{ ngx_string("http"),
NGX_MAIN_CONF | NGX_CONF_BLOCK | NGX_CONF_NOARGS,
ngx_http_block,
0,
0,
NULL
},
ngx_null_command
};
ngx_module_t ngx_http_module = {
NGX_MODULE_V1,
&ngx_http_module_ctx,
ngx_http_commands,
NGX_CORE_MODULE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NGX_MODULE_P1_PADDING
};
在ngx_http_block中将cf->module_type设置为NGX_HTTP_MODULE,解析http块配置项中的其他配置项时,找到对应的http模块并进行后续处理,而所有http模块的类型均定义为NGX_HTTP_MODULE。 这样,可有效防止配置项被其他模块所处理。
- 配置项类型:与模块类型类似
if(!(cmd->type & cf->cmd_type)){
continue;
}
cmd->type初始值为NGX_MAIN_CONF,前面提到的ngx_http_module模块的配置项数组中http配置项的类型包含了NGX_MAIN_CONF。
- 配置项值的个数
前面提到每个配置项名后可以有多个配置项值,当前配置项值的最大个数定义为8。代码中有相关的宏对应。配置项值的个数必须正确才能进行实际的配置项解析。
#define NGX_CONF_MAX_ARGS 8
#define NGX_CONF_NOARGS 0x00000001 //无配置项值
#define NGX_CONF_TAKE1 0x00000002 //接受1个配置项值
#define NGX_CONF_TAKE2 0x00000004 //接受2个配置项值
#define NGX_CONF_TAKE3 0x00000008 //接受3个配置项值
#define NGX_CONF_TAKE4 0x00000010 //接受4个配置项值
#define NGX_CONF_TAKE5 0x00000020 //接受5个配置项值
#define NGX_CONF_TAKE6 0x00000040 //接受6个配置项值
#define NGX_CONF_TAKE7 0x00000080 //接受7个配置项值
#define NGX_CONF_BLOCK 0x00000100 //接受块配置项
#define NGX_CONF_FLAG 0x00000200 //接受配置项值为on或者off
#define NGX_CONF_ANY 0x00000400 //接受任意的配置项值
#define NGX_CONF_1MORE 0x00000800 //至少1个配置项值
#define NGX_CONF_2MORE 0x00001000 //至少2个配置项值
#define NGX_CONF_MULTI 0x00000000 //接受多个配置项值 个数不定
//接受1个或2个配置项值
#define NGX_CONF_TAKE12 (NGX_CONF_TAKE1|NGX_CONF_TAKE2)
//接受1个或3个配置项值
#define NGX_CONF_TAKE13 (NGX_CONF_TAKE1|NGX_CONF_TAKE3)
//接受2个或3个配置项值
#define NGX_CONF_TAKE23 (NGX_CONF_TAKE2|NGX_CONF_TAKE2)
//接受1个或2个或3个配置项值
#define NGX_CONF_TAKE123 (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3)
//接受1个或2个或4个配置项值
#define NGX_CONF_TAKE1234 (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3|NGX_CONF_TAKE4)
参考:
《深入理解nginx》
《nginx开发从入门到精通》
来源:oschina
链接:https://my.oschina.net/u/184909/blog/690782