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

前面提到中我们已经了解到了变量容器的生命周期时与请求绑定的,但是我们当时有意避开了“请求”的正式定义。大家应当一直默认这里的“请求”都是指客户端发起的HTTP请求。其实在nginx世界里有两种类型的“请求”。一种叫做“主请求”另一种则叫做“子请求”。我们先来介绍一下它们。

所谓“主请求”则是有nginx正在处理的请求在nginx内部发起的一种级联请求。“子请求”在外观上很想HTTP请求,但现实上却和HTTP协议乃至网络通信一点关系都没有。它是一种抽象调用,目的是为了方便访问多个location接口,然后由这些location接口通力协作,共同完成整个“主请求”。当然,”子请求“的概念是相对的,任何一个”子请求“也可以发起更多的”子请求“,甚至可以玩递归调用(即自己调用自己)。当一个请求发起一个”子请求“的时候,按照nginx的术语,习惯把前者称为后者的”父请求“。值得一提的是,apache服务器中其实也有”子请求“的概念,所以来自apache世界的读者对此应该不会陌生。

下面我们来看一个“子请求"的例子:

location /main {

echo_location /foo;

echo_locatioj /bar;

}

location /foo {

echo foo;

}

location /bar {

echo bar;

}



这里的location /main 中,通过第三方ngx_echo模块echo_location 指令分别发起到/foo和/bar这两个接口的GET类型的”子请求“。由echo_location发起的”子请求“,其执行是按照配置书写的顺寻串行处理的,即只有当/foo请求处理完毕之后,才会接着处理/bar请求。这两个”子请求“的输出会按照执行顺寻拼接起来,作为/main接口的最终输出:

$curl 'http://location:8080/main'

foo

bar

我们看到了,”子请求“方式的通信是在一个虚拟主机内部进行的,所以ngin的核心在实现'子请求”的时候,就只调用了若干个C函数,完全不涉及任何网络或者UNIX台阶字通信。我们由此可以看出“子请求”的执行效率是极高的。

先回到先前对nginx变量值容器的生命周期的讨论,我们现在依旧可以说,它们的生命周期是与当前请求相关联的。每个请求都有所有变量值容器的独立副本,只不过当前请求既可以是“主请求”,也可以是“子请求”。即便是父子请求之间,同名变量一般也不会相互干扰。我们来通过一个小实验证明一下这个说法:

locating /main {

set $var main:

echo_location /foo;

echo_location /bar;

echo "main:$var";

}

location /foo {

set $var foo;

echo "foo: $var";

}

location /bar {

set $var bar;

echo "bar:$var";

}

在这个例子中,我们分别在/main,/foo和/bar这三个location配置块中为同一名字的变量,$var,分别设置了不同的值并予以输出。特备地,我们在。/main接口中,故意在调用/foo和/bar这连个“子请求"之后,再输出它的$var变量的值。请求/main接口的结果是这样的:

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

foo:foo

bar:bar

main:main

显然,/foo和/bar这两个”子请求“在处理过程中对变量$var各自所做的修改都丝毫没有影响到”主请求“/main。于是这成功的印证了”主请求“以及各个”子请求“都拥有不同的变量$var的值容器副本。

不幸的是,一些nginx模块发起的”子请求“却会自动共享其”父请求“的变量值容器,比如第三方模块ngx_auth_request下面是一个例子:

location /main { 

set $ var main:

auth_request /sub;

echo "main:$var";

}


location /sub {

set $var sub;

echo "sub:$var";

}

这里我们在/main接口中先为$var变量赋初值main,然后使用mgx_auth_request模块提供的配置指令auth_request,发起一个到/sub接口中故意把$var变量的值改写成sub。访问。main接口的结果如下:

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

main:sub

我们看到,/sub接口对$var变量的修改影响到了主请求/main。所以ngx_auth_request模块发起的”子请求“确实与其”父请求“共享一套nginx变量的值容器。

对于上面的这个例子,相信有读者会问:为什么’子请求‘ /sub的输出没有出现在最终的输出里面呢?”答案很简单,那就是因为auth_request指令会自动忽略“子请求”的响应体,而只检查“子请求”的响应状态码。当状态码是2XX的时候,auth_request指令会忽略“子请求”而让nginx继续处理当前请求的执行,返回响应的错页。在我们的例子中 /sub“子请求”只是使用echo指令作了一些输出,所以隐式地返回了指示正常的200状态码。

如ngx_auth_request模块这样的父子请求共享一套nginx变量的行为,虽然可以让父子请求之间的数据双向传递变得即为容易,但是对于足够复杂的配置,却页经常导致不少难以调试的bug。因为用户经常不知道“父请求”的某个nginx变量的值,其实已经在它的某个“子请求”中被意外修改了。诸如此类的因共享而导致的不好的“副作用”,让包括ngx_echo,ngx_lua,以及ngx_sracche在内的许多第三方模块选择了禁用父子请求间的变量共享。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值