nginx的配置由一个主配置文件和其余一些辅助的配置文件构成。这些配置文件均是纯文本文件,这些配置文件所有位于nginx安装目录下的conf目录中。html
主配置文件nginx.conf中的内容大概是这样子的:nginx
#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分隔。简单配置项的结尾使用分号结束,其基本的语法格式以下:bash
配置项名 配置项值1 配置项值2 ... ;
块配置项由一个配置项名和一对大括号组成,其结尾不须要再添加分号。块配置项使用大括号把一系列所属的配置项所有包含起来,表示大括号内的配置项同时生效;块配置项也能够有配置项值,这取决于解析这个配置项的模块;块配置项能够嵌套,内层块直接继承外层块,同一个配置项能够同时出如今内外层块配置项中,其优先级也取决于解析该配置项的模块。app
nginx配置解析的流程基本上是一个递归的过程,以下图所示:函数
在配置解析的入口函数 ngx_conf_parse 中会循环读取配置文件中的内容,每读取一行后就解析该配置项。解析的过程当中可能会再次调用该函数完成后续配置项的解析,例如events块配置项,http块配置项的解析。spa
对应的源码:命令行
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函数支持三种不一样的解析环境:code
从前面的解析流程能够看出,首次调用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开发从入门到精通》