nginx(2)变量转载自章亦春

来源:互联网 发布:金和软件官网 编辑:程序博客网 时间:2024/06/03 13:34

关于nginx变量的另一个常见误区是认为变量容器的生命周期,是与location配置块绑定的。其实不然,我们来看一个涉及“内部跳转”的例子:

server{

listen 8080;

location /foo {

set $a hello;

echo_exec /bar;

}

location /bar {

echo "a = [$a]";

}

}

这里我们在location /foo中,使用第三方模块ngx_echo提供的echo_exec 配置指令,发起到location /bar的“内部跳转”,就是在处理请求的过程中,于服务器内部,从一个location跳转到另一个location的过程。这不同于利用HTTP状态码内301和302所进行的“外部跳转”,因为后者是由HTTP客户端配合进行跳转的,而在客户端,用户可以通过浏览器地址栏这样的界面,看到请求的URL地址发生了变化。内部跳转和bourne shell(或bash)中的exec命令很像,都是“有去无回”。另一个相近的例子是C语言的goto语句。

$ curl localhost:8080/foo

a = [hello]

如果我们从客户端直接访问/bar接口,就会得到空的$a变量的值,因为它依赖于location /foo来对$a进行初始化。

从上面的这个例子我们看到,一个请求在其处理过程中,即使经历多个不同的location配置块,它使用的还是同一套nginx变量的副本。这里,我们也首次涉及到了“内部跳转”这个概念。值得一提的是,标准的ngx_rewrite模块rewrite配置指令其实也可以发起“内部跳转”,例如上面的那个例子用rewrite配置指令可以改写成下面的这样形式:

server{

listen 8080;

location /foo{

set $a hello;

rewrite ^ /bar;

}

location /bar {

echo"a = [$a]";

}

}


其效果和使用echo_exec是完全一样的。后面我们还专门介绍了这个rewrite指令的更多用法,比如发起301和302这样的“外部跳转”。

从上面这个例子我们看出,nginx变量值容器的生命周期是与当前正在处理的请求绑定的,而与location无关。

前面我们接触到的都是通过set指令隐式创建的nginx变量。这些变量我们一般称之为“用户自定义变量”,或者更简单一点“用户变量”。既然有“用户自定义变量”,自然也就有由nginx模块提供的“预定义变量”,或者称“内建变量”。

nginx内建变量最常见的用途就是获取关于请求或响应的各种信息。例如由ngx_http_core模块提供的内建变量$uri,可以用来获取当前请求的URI,而$requet_uri则用来获取请求最原始的URI。请看下面例子:

location /test {

echo "uri = $uri";

echo "request_uri = $request_uri";

         }

这里为了简单起见,连server配置块也省略了,和前面所有实例一样,我们所监听的依然式8080端口。在这个例子里,我们打$uri和$request_uri的值输出到响应体中去。虾米那我们用不同的请求来测试一下这个/test接口:

$curl 'http://localhost:8080/test'

uri = /test

requset_uri = /test

$curl 'http://localhost:8080/test?a=3&b=4'

uri = /test

request_uri = /test?a=3&b=4

$curl 'http://localhost:8080/test/hello%20world?a=3&b=4'

uri = /test/hello world

request_uri = /test/hello%20world?a=3&b=4

另一个特别常用的内建变量其实并不是我们单独一个变量,而是有无线多种变量的一群变量,即名字以arg_开头的多有变量,我们姑且称之为$arg_xxx 变量群。一个例子是$arg_name,这个变量的值是当前请求名为name的URI参数的值,而且还是未解码的原始形式的值,我们来看一个比较完整的例子:


location /test{

echo "name:$arg_name";

echo"class:$arg_class";

}

然后在命令行上使用各种参数组合去请求这个/test接口:

$ curl 'http://localhost:8080/test'

name:

class:

$ curl ‘http://localhost:8080/test?test?name=Tom&class=3'

name:Tom

class:3

$ curl 'http://localhost:8080/test?name=hello%20world&class=9'

name:hello%20world

class:9


其实$arg_name 不仅可以匹配name参数,也可以匹配NAME参数,抑或是Name,等等:

$ curl 'http://localhost:8080/test?NAME=Marry'

name:Marry

class:


$ curl 'http://localhost:8080/test?Name=Jimmy'

name:Jimmy

class:

nginx会在匹配参数名之前,自动把原始请求中的参数名调整为全部小写形式。

如果你想对URI参数值中的%xx这样的编码序列进行解码,可以使用第三方ngx_set_misc模块提供的set_unescape_uri配置指令:

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

空格果然被解码出来了!


原创粉丝点击