nginx变量定义
nginx使用“$”符号作为前缀来表示一个变量,并且它还有一个其它语言没有的特性:变量可以直接插入到一个字符串中,插入后并不会改变变量的特性,并且对插入变量的个数没有限制。除了直接在变量名字前加“$”符号表示一个变量外,nginx中还有另外一种形式来表示变量:在“$”符号的基础上加上一对花括号,并把变量名放在花括号中,比如:
set ${a} “hello”
set ${b} “world”
nginx对表示变量名的字符也是有规定的,nginx中仅允许四种类型的字符或他们的组合做为变量名,分别是大写字母(A-Z)、小写字母(a-z)、数字(0-9)、下划线(_),其它都是非法的。只有某个变量在真正被使用的时候nginx才会检查变量名的合法性,比如set指令中的为定义的变量赋值就是一种“使用”,而被定义的变量不能叫“使用”。
在nginx中变量的定义又分了两种:
- 一种是自定义变量,就如上面用set指令设置的变量,它会在配置文件中明确指出这是一个被定义的变量,当然并不是说自定义变量就一定要使用set指令。如ngx_http_geo模块是nginx的自带的一个标准模块,该模块只包含一个指令geo,作用是根据客户端ip来定义一个变量:
另外一个显著的不同是set指令定义的变量值是一个字符串形式,而geo定义的变量值则需要使用花括号括起来,并且该指令内部还隐含的做了逻辑判断。比如如果客户端ip地址是127.0.0.1则该变量值是“客户端ip是127.0.0.1”,如果不是则就是默认值“我是geo默认值”。默认情况下geo指令会自己获取客户端的ip,然后根据相应的配置去映射变量,但其实它也可以接收一个指定ip,如:http { geo $a { default “我是geo默认值”; 127.0.0.1 “客户端ip是127.0.0.1”; } location / { return 200 “$a”; } }
geo $arg_name $a { default “我是geo默认值”; 127.0.0.1 “我是张三”; 192.168.1.1 “我是李四”; } location / { return 200 “$a”; }
验证一下看看效果:curl http://127.0.0.1/?name=127.0.0.1 -- 返回我是张三
- 另外是内置变量,它在nginx启动之前就已经被设置好了,不需要在配置文件中明确定义。另外内置变量也是分模块的,每个模块都可以有自己的内置变量,比如$uri这个内置变量就属于ngx_http_core这个http核心模块中的变量,关于这个模块的其它内置变量读者可以关注nginx的官方文档: Module ngx_http_core_module
动态内置变量
在之前的小节中有用到“$uri”这个变量来说明内置变量,但是并没有提到内置变量的另外一种形式,即动态内置变量。这里所谓“动态”指的是变量的名字是不确定的,这个不确定性发生在nginx的运行过程中。目前在nginx的http模块中有六种内置动态变量,分别是“http_”、“sent_http_”、“upstream_http_”、“upstream_cookie”、“cookie_”,“arg_”。
- 以“http_”开头的动态内置变量可以表示http请求过程中的任意请求头,使用的过程中不区分大小写,并且请求头中如果有“-”字符需要用“_”字符替代,如:
location / { return 200 “User-Agent: $http_user_agent ”; } curl http://nginx.org/en/dosc/ -v 请求: > GET /en/docs HTTP/1.1 > User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2 > Host: nginx.org > Accept: */* 应答: curl http://127.0.0.1/ User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
- 以“sent_http_”开头的动态内置变量可以表示http响应过程中的任意响应头,规则跟“http_”动态内置变量一样,如:
location /a {
return 200 “I am $sent_http_connection”;
}
curl http://127.0.0.1/a -v
响应头:
< Server: nginx/1.9.4
< Date: Sat, 21 Apr 2018 09:04:36 GMT
< Content-Type: application/octet-stream
< Content-Length: 15
< Connection: keep-alive
curl http://127.0.0.1/a
I am keep-alive
- 以“cookie_”开头的动态内置变量可以表示http请求过程中的某个cookie值。需要和“$http_cookie”这个内置变量(非动态内置变量)区分一下,它代表请求中整个cookie值。 而以“cookie_”开头的变量则代表某个实际cookie值,比如“$cookie_a”代表本次请求中cookie名字是a的对应值。
- 以“arg_”开头的动态内置变量,用法跟以“cookie_”开头的变量类似,就不再赘述了。在nginx中变量“$arg_”不代表任何入参值,它会被nginx转换成空字符,若$arg_变量(这种不合法),最终也就是输出“变量”字符串。
可变变量和不可变变量
nginx中的变量也存在可变和不可变之分,但是它并没有显著的修饰符,所以从表面上你根本看不出来该变量是否可变。不过nginx在启动过程中提供了一个自检查机制,当在配置文件中试图修改一个不可变变量时,nginx是不会顺利启动的。通过这种机制可以间接的判断某个变量是否可变。目前nginx的核心http模块中几乎所有内置变量都是不可改变的,只有“$args”和“$limit_rate”这两个内置变量可以被改变。
可缓存变量和不可缓存变量
nginx中所有的变量在定义的时候都会被关联上一个get_handler()方法,所有变量在第一次获取值的时候,都是通过这个handler方法获取的,后续再次获取变量值的时候,是否仍然调用该handler方法则取决于该变量是否可以被缓存。
不可缓存的变量在获取值的时候都是实时计算的,比如“$arg_”开头的动态变量,每次获取值的时候都会从查询参数中重新解析对应的值;而可以缓存的变量并不会每次都调用这个handler方法,在它的整个生命周期中,如果这个变量没有被刷新过,那么自始至终只会调用一次。
nginx中用set指令定义的变量都是可以缓存的,但set指令不会改变已有变量的缓存特性(比如内置变量,但动态变量除外),而所有以“arg_”开头的动态变量都是不可缓存的。
动态内置变量此时仍然是一个特殊的存在,我们之前说过,动态变量被重新定义后它就不再是动态变量了,所以它也就不再保有不可缓存的特性。