根据上一篇文章「系统架构」Nginx调优之变量的使用(1)中的描述,相信大家已经大致了解了Nginx中的变量,知道了可以使用“$”符号作为前缀来表示一个变量,也知道了可以将定义好的变量直接作为字符串的一部分插入字符串中等。但是你们知道在Nginx中有哪些内置变量吗?知道如何定义一个变量才是合法吗?ok,下面我们来详细介绍此部分内容。
表示变量的有效字符
在大部分编程语言中并不是所有的字符都可以用来表示变量名,一般会有一个范围限制,如在PHP中,变量只能包含字母、数字、下划线,而且数字不能变量的开始。nginx对表示变量名的字符也是有规定的,nginx中仅允许四种类型的字符或他们的组合做为变量名,分别是大写字母(A-Z)、小写字母(a-z)、数字(0-9)、下划线(_),其它都是非法的。
内置变量和自定义变量
在nginx中,变量在使用之前是需要预先定义的。在有些语言中当你使用了未定义的变量后可能是编译无法通过,而在nginx则会导致nginx无法正常启动。
在nginx中变量的定义分了两种:一种是自定义变量,就是上面用set指令设置的变量,它会在配置文件中明确指出这是一个被定义的变量。另外是内置变量,它在nginx启动之前就已经被设置好了,不需要在配置文件中明确定义。
需要注意,并不是说自定义变量就一定要使用set指令,nginx中可以自定义变量的模块有很多,之所以一直在用set指令讲解变量,是因为我希望读者把更多的注意里放到变量本身上来,尽量避免为了说明一个问题而又引入其它额外的问题。比如,我们下面要用到的ngx_geo模块,这就是nginx的自带的一个标准模块,该模块只包含一个指令geo,作用是根据客户端ip来定义一个变量。
http { geo $a { default “我是geo默认值”; 127.0.0.1 “客户端ip是127.0.0.1”; } location / { return 200 “$a”; }}
我们用curl访问以下这个资源看看效果:
curl http://127.0.0.1/客户端ip是127.0.0.1
可以看到变量$a的值变成了geo指令中设定的值。
同样是定义变量,geo指令跟set指令且有很大的不同。比如,指令的放置位置,set指令可以放在location块中,而geo指令则只能放在http块中。
另外一个显著的不同是,set指令定义的变量值是一个字符串形式,而geo定义的变量值则需要使用花括号括起来,并且该指令内部还隐含的做了逻辑判断。比如如果客户端ip地址是127.0.0.1,则该变量值是“客户端ip是127.0.0.1”,如果不是,则就是默认值“我是geo默认值”。
默认情况下geo指令会自己获取客户端的ip,然后根据相应的配置去映射变量,但其实它也可以接收一个指定ip,比如下面的例子:
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我是张三curl http://127.0.0.1/?name=192.168.1.1我是李四
把入参name去掉再看看效果:
curl http://127.0.0.1/我是geo默认值
这里既然用到ngx_geo模块,那我们就回过头来在看看之前提到的变量插入的问题,之前说过并不是所有的模块都支持变量插入的,ngx_geo就是这样一个模块。在geo指令中的花括号中是没有变量这一说的,在geo的花括号中放入的变量只会原样展示,比如下面的例子:
geo $a { default “我是geo默认值 $arg_name”; 127.0.0.1 “我是张三 $arg_name”;}location / { return 200 “$a”;}
当你试图用一个带着name参数的请求访问这个locaiton的时候,它会把花括号中对应的值原样输出:
curl http://127.0.0.1我是张三$arg_name
除了自定义变量,nginx中的另一种变量就是内置变量了,内置变量在nginx启动之前就已经被设置好了,不需要在配置文件中明确定义。
来看一个内置变量的例子:
location /{ return200 “$uri”}
按照我们目前的知识,基于上面的配置nginx应该无法启动才对,因为在配置文件中我们没有对变量“$uri”做定义,但事实上它不但可以启动成功,而且还可以很好的工作,用curl检测一下:
curl http://127.0.0.1/abc
打印结果如下:
/abc
这其实就是因为变量“$uri”是一个内置变量,他在nginx内部已经提前定义好了。
另外,内置变量也是分模块的,每个模块都可以有自己的内置变量。比如,$uri这个内置变量就属于ngx_http_core这个http核心模块中的变量。关于这个模块的其它内置变量,读者可以关注nginx的官方文档: http://nginx.org/en/docs/http/ngx_http_core_module.html#variables