变量
只能存放字符串
用户变量
通过
set
指令创建的nginx
变量
1 2 3 |
set $a hello world//hello world set $b "\$a, \$a"//hello world, hello world |
1 2 3 4 5 6 7 |
server { listen 8080; location /test { set $foo "hello"; echo "foo: $foo"; } } |
通过不支持“变量插值”的模块配置指令专门构造出取值为\$的
Nginx
变量,然后再在echo
中使用这个变量
1 2 3 4 5 6 7 8 9 10 11 |
//输出$ geo $dollar { default "$"; } server { listen 8080; location /test { echo "this is a dollar sign: $dollar"; } } |
1 2 3 4 5 6 7 8 |
//变量用于拼接字符串 server { listen 8080; location /test { set $first "hello "; echo "${first}world"; } } |
nginx变量一旦创建,变量名的可见范围就是整个nginx配置。但是,当操作的时候,其实操作的是自个持有的副本内容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
server { listen 8080; location /foo { echo "foo = [$foo]"; } location /bar { set $foo 32; echo "foo = [$foo]"; } } //curl 'http://localhost:8080/foo' // foo = [] //curl 'http://localhost:8080/bar' //foo = [32] //curl 'http://localhost:8080/foo' //foo = [] |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
//变量的“内部跳转” echo_exec server { listen 8080; location /foo { set $a "hello"; echo_exec /bar; } location /bar { echo "a = [$a]"; } } //rewrite实现 server { listen 8080; location /foo { set $a hello; rewrite ^ /bar; } location /bar { echo "a = [$a]"; } } |
nginx
变量容器的生命期是与当前正在处理的请求绑定的,而与location
无关。
内建变量
ngx_http_core
模块
- \$uri
- 用来获取当前请求的URI(经过解码,并且不包含请求参数)
- \$request_uri
- 用来获取最原始的URI(未经过解码,并且包含请求参数)
1 2 3 4 |
location /test { echo "uri = $uri"; echo "request_uri = $request_uri"; } |
\$arg_xxx
- \$arg_name
- 当前请求名为
name
的 URI 参数的值,而且还是未解码的原始形式的值 - 不仅可以匹配
name
参数,也可以匹配NAME
参数,抑或是Name
,等等
- 当前请求名为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
location /test { echo "name: $arg_name"; echo "class: $arg_class"; } //$ curl 'http://localhost:8080/test' //name: //class: //$ curl 'http://localhost:8080/test?name=Tom&class=3' //name: Tom //class: 3 //$ curl 'http://localhost:8080/test?name=hello%20world&class=9' //name: hello%20world //class: 9 |
ngx_set_misc
模块
set_unescape_uri
- 对 URI 参数值中的
%XX
这样的编码序列进行解码
- 对 URI 参数值中的
1 2 3 4 5 6 7 8 9 10 11 |
location /test { set_unescape_uri $name $arg_name; set)unescape_uri $class $arg_class; echo "name: $name"; echo "class: $class"; } //$ curl 'http://localhost:8080/test?name=hello%20world&class=9' //name: hello world //class: 9 |
应避免对这种内建变量进行赋值。
可变值内建变量
也有一些内建变量是支持改写的,如\$args,这个变量在读取时返回当前请求的 URL 参数串(即请求 URL 中问号后面的部分,如果有的话),而在赋值时可以直接修改参数串。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
location /test { set $orig_args $args; set $args "a=3&b=4"; echo "original args: $orig_args"; echo "args: $args"; } //$ curl 'http://localhost:8080/test' //original args: //args: a=3&b=4 //$ curl 'http://localhost:8080/test?a=0&b=1&c=2' //original args: a=0&b=1&c=2 //args: a=3&b=4 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
server { listen 8080; location /test { set $args "foo=1&bar=2"; proxy_pass http://127.0.0.1:8081/args; } } server { listen 8081; location /args { location /args { echo "args: $args"; } } } |
这里在
http
配置块中定义了两个虚拟主机。第一个虚拟主机监听 8080 端口,其/test
接口自己通过改写 $args 变量,将当前请求的 URL 参数串无条件地修改为foo=1&bar=2
. 然后/test
接口再通过 ngx_proxy 模块的 proxy_pass 指令配置了一个反向代理,指向本机的 8081 端口上的 HTTP 服务/args
. 默认情况下, ngx_proxy 模块在转发 HTTP 请求到远方 HTTP 服务的时候,会自动把当前请求的 URL 参数串也转发到远方。而本机的 8081 端口上的 HTTP 服务正是由我们定义的第二个虚拟主机来提供的。我们在第二个虚拟主机的
location /args
中利用 echo 指令输出当前请求的 URL 参数串,以检查/test
接口通过 ngx_proxy 模块实际转发过来的 URL 请求参数串。
变量映射
在设置了“取处理程序”的情况下,
Nginx
变量也可以选择将其值容器用作缓存,这样在多次读取变量的时候,就只需要调用“取处理程序”计算一次。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
map $args $foo { default 0; debug 1; } server { listen 8080; location /test { set $orig_foo $foo; set $args debug; echo "original foo: $orig_foo"; echo "foo: $foo"; } } |
这里用到了标准 ngx_map 模块的 map 配置指令,我们有必要在此介绍一下。
map
在英文中除了“地图”之外,也有“映射”的意思。比方说,中学数学里讲的“函数”就是一种“映射”。而 Nginx 的这个 map 指令就可以用于定义两个 Nginx 变量之间的映射关系,或者说是函数关系。回到上面这个例子,我们用 map 指令定义了用户变量 \$foo 与 $args 内建变量之间的映射关系。特别地,用数学上的函数记法y = f(x)
来说,我们的 \$args 就是“自变量”x
,而 \$foo 则是“因变量”y
,即 \$foo的值是由 $args 的值来决定的,或者按照书写顺序可以说,我们将 $args 变量的值映射到了 \$foo 变量上。
1 2 3 4 |
map $args $foo { default 0; debug 1; } |
第一行的
default
是一个特殊的匹配条件,即当其他条件都不匹配的时候,这个条件才匹配。当这个默认条件匹配时,就把“因变量” \$foo 映射到值0
。花括号中第二行的意思是说,如果“自变量” \$args 精确匹配了
debug
这个字符串,则把“因变量” \$foo 映射到值1
. 将这两行合起来,我们就得到如下完整的映射规则:当 $args 的值等于debug
的时候,\$foo 变量的值就是1
,否则 \$foo 的值就为0
。
明白了 map 指令的含义,再来看
location /test
. 在那里,我们先把当前 \$foo 变量的值保存在另一个用户变量 \$orig_foo 中,然后再强行把 $args 的值改写为debug
,最后我们再用 echo 指令分别输出 \$orig_foo 和 \$foo 的值。从逻辑上看,似乎当我们强行改写 $args 的值为
debug
之后,根据先前的 map 映射规则,\$foo 变量此时的值应当自动调整为字符串1
, 而不论 \$foo 原先的值是怎样的。然而测试结果并非如此:
1 2 3 |
$ curl 'http://localhost:8080/test' original foo: 0 foo: 0 |
第一行输出指示 \$orig_foo 的值为
0
,这正是我们期望的:上面这个请求并没有提供 URL 参数串,于是 $args 最初的取值就是空,再根据我们先前定义的映射规则,\$foo 变量在第一次被读取时的值就应当是0
(即匹配默认的那个default
条件)。而第二行输出显示,在强行改写 $args 变量的值为字符串
debug
之后,\$foo 的条件仍然是0
,这显然不符合映射规则,因为当 $args 为debug
时,\$foo 的值应当是1
. 这究竟是为什么呢?其实原因很简单,那就是 \$foo 变量在第一次读取时,根据映射规则计算出的值被缓存住了。刚才我们说过,Nginx 模块可以为其创建的变量选择使用值容器,作为其“取处理程序”计算结果的缓存。显然, ngx_map 模块认为变量间的映射计算足够昂贵,需要自动将因变量的计算结果缓存下来,这样在当前请求的处理过程中如果再次读取这个因变量,Nginx 就可以直接返回缓存住的结果,而不再调用该变量的“取处理程序”再行计算了。
本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ Nginx 变量二10/29
- ♥ VMaware:不显示共享文件夹的解决09/14
- ♥ Chromium:学习,Widget,二09/03
- ♥ COM组件_101/31
- ♥ cef:任务、IPC、网络相关04/30
- ♥ 后端知识点记述 一09/08