在设置nginx配置文件的时候,配置文件中会出现$file等以$开头的字符串。这些以$开头的字符串在nginx中就是所谓的变量。nginx的变量分为nginx自定义的变量以及用户自定义的变量。nginx自定义的变量有很多,每个模块也可以定义自己的变量,例如ngx_http_core_variables这个就包含了很多nginx自定义的变量:
static ngx_http_variable_t ngx_http_core_variables[] = {
{ ngx_string("http_host"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_in.host), 0, 0 },
{ ngx_string("http_user_agent"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_in.user_agent), 0, 0 },
{ ngx_string("http_referer"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_in.referer), 0, 0 },
#if (NGX_HTTP_GZIP)
{ ngx_string("http_via"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_in.via), 0, 0 },
#endif
#if (NGX_HTTP_X_FORWARDED_FOR)
{ ngx_string("http_x_forwarded_for"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_in.x_forwarded_for), 0, 0 },
#endif
{ ngx_string("http_cookie"), NULL, ngx_http_variable_headers,
offsetof(ngx_http_request_t, headers_in.cookies), 0, 0 },
{ ngx_string("content_length"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_in.content_length), 0, 0 },
{ ngx_string("content_type"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_in.content_type), 0, 0 },
.....
}
而用户自定义的变量一般都是用set命令来定义的。下面先来介绍两个关于变量的结构体:
struct ngx_http_variable_s {
ngx_str_t name; /* must be first to build the hash */
ngx_http_set_variable_pt set_handler;
ngx_http_get_variable_pt get_handler;
uintptr_t data;
ngx_uint_t flags;
ngx_uint_t index;
};
typedef struct {
unsigned len:28;
unsigned valid:1;
unsigned no_cacheable:1;
unsigned not_found:1;
unsigned escape:1;
u_char *data;
} ngx_variable_value_t;
从结构体名字来看这两个结构体差不多能构成key-value。但是在ngx_variable_value_t本身也带有data,这个data看似是存放值的地方,那为什么还需要用到ngx_variable_value_t呢?等到下面再讲。
在解析配置文件之前,nginx会把所有nginx自定义的变量统一规划起来,规划到http核心配置ngx_http_core_main_conf_t的variables_keys字段内。nginx几乎每个模块都可以定义自己的变量,每个模块都是通过自己的preconfiguration把变量统一规划起来的。
static char *
ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
......
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
continue;
}
module = ngx_modules[m]->ctx;
if (module->preconfiguration) {
if (module->preconfiguration(cf) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
}
/* parse inside the http{} block */
cf->module_type = NGX_HTTP_MODULE;
cf->cmd_type = NGX_HTTP_MAIN