与 $arg_XXX 类似,我们在 (二) 中提到过的内建变量 $cookie_XXX 变量也会在名为 XXX
的 cookie 不存在时返回特殊值“没找到”:
location /test {
content_by_lua '
if ngx.var.cookie_user == nil then
ngx.say("cookie user: missing")
else
ngx.say("cookie user: [", ngx.var.cookie_user, "]")
end
';
}
利用 curl
命令行工具的 --cookie name=value
选项可以指定 name=value
为当前请求携带的 cookie(通过添加相应的 Cookie
请求头)。下面是若干次测试结果:
$ curl --cookie user=agentzh 'http://localhost:8080/test'
cookie user: [agentzh]
$ curl --cookie user= 'http://localhost:8080/test'
cookie user: []
$ curl 'http://localhost:8080/test'
cookie user: missing
我们看到,cookie user
不存在以及取值为空字符串这两种情况被很好地区分开了:当 cookie user
不存在时,Lua 代码中的 ngx.var.cookie_user
返回了期望的 Lua nil
值。
在 Lua 里访问未创建的 Nginx 用户变量时,在 Lua 里也会得到 nil
值,而不会像先前的例子那样直接让 Nginx 拒绝加载配置:
location /test {
content_by_lua '
ngx.say("$blah = ", ngx.var.blah)
';
}
这里假设我们并没有在当前的 nginx.conf
配置文件中创建过用户变量 $blah
,然后我们在 Lua 代码中通过ngx.var.blah
直接引用它。上面这个配置可以顺利启动,因为 Nginx 在加载配置时只会编译 content_by_lua配置指令指定的 Lua 代码而不会实际执行它,所以 Nginx 并不知道 Lua 代码里面引用了 $blah
这个变量。于是我们在运行时也会得到 nil
值。而 ngx_lua 提供的 ngx.say 函数会自动把 Lua 的 nil
值格式化为字符串"nil"
输出,于是访问 /test
接口的结果是:
curl 'http://localhost:8080/test'
$blah = nil
这正是我们所期望的。
上面这个例子中另一个值得注意的地方是,我们在 content_by_lua 配置指令的参数中提及了 $bar
符号,但却并没有触发“变量插值”(否则 Nginx 会在启动时抱怨 $blah
未创建)。这是因为 content_by_lua 配置指令并不支持参数的“变量插值”功能。我们前面在 (一) 中提到过,配置指令的参数是否允许“变量插值”,其实取决于该指令的实现模块。
设计返回“不合法”这一特殊值的例子是困难的,因为我们前面在 (七) 中已经看到,由 set 指令创建的变量在未初始化时确实是“不合法”,但一旦尝试读取它们时,Nginx 就会自动调用其“取处理程序”,而它们的“取处理程序”会自动返回空字符串并将之缓存住。于是我们最终得到的是完全合法的空字符串。下面这个使用了 Lua 代码的例子证明了这一点:
location /foo {
content_by_lua '
if ngx.var.foo == nil then
ngx.say("$foo is nil")
else
ngx.say("$foo = [", ngx.var.foo, "]")
end
';
}
location /bar {
set $foo 32;
echo "foo = [$foo]";
}
请求 /foo
接口的结果是:
$ curl 'http://localhost:8080/foo'
$foo = []
我们看到在 Lua 里面读取未初始化的 Nginx 变量 $foo
时得到的是空字符串。
最后值得一提的是,虽然前面反复指出 Nginx 变量只有字符串这一种数据类型,但这并不能阻止像ngx_array_var 这样的第三方模块让 Nginx 变量也能存放数组类型的值。下面就是这样的一个例子:
location /test {
array_split "," $arg_names to=$array;
array_map "[$array_it]" $array;
array_join " " $array to=$res;
echo $res;
}
这个例子中使用了 ngx_array_var 模块的 array_split
、 array_map
和 array_join
这三条配置指令,其含义很接近 Perl 语言中的内建函数 split
、map
和 join
(当然,其他脚本语言也有类似的等价物)。我们来看看访问 /test
接口的结果:
$ curl 'http://localhost:8080/test?names=Tom,Jim,Bob
[Tom] [Jim] [Bob]
我们看到,使用 ngx_array_var 模块可以很方便地处理这样具有不定个数的组成元素的输入数据,例如此例中的 names
URL 参数值就是由不定个数的逗号分隔的名字所组成。不过,这种类型的复杂任务通过 ngx_lua 来做通常会更灵活而且更容易维护。
至此,本系列教程对 Nginx 变量的介绍终于可以告一段落了。我们在这个过程中接触到了许多标准的和第三方的 Nginx 模块,这些模块让我们得以很轻松地构造出许多有趣的小例子,从而可以深入探究 Nginx 变量的各种行为和特性。在后续的教程中,我们还会有很多机会与这些模块打交道。
通过前面讨论过的众多例子,我们应当已经感受到 Nginx 变量在 Nginx 配置语言中所扮演的重要角色:它是获取 Nginx 中各种信息(包括当前请求的信息)的主要途径和载体,同时也是各个模块之间传递数据的主要媒介之一。在后续的教程中,我们会经常看到 Nginx 变量的身影,所以现在很好地理解它们是非常重要的。
在下一个系列的教程,即 Nginx 配置指令的执行顺序系列 中,我们将深入探讨 Nginx 配置指令的执行顺序以及请求的各个处理阶段,因为很多 Nginx 用户都搞不清楚他们书写的众多配置指令之间究竟是按照何种时间顺序执行的,也搞不懂为什么这些指令实际执行的顺序经常和配置文件里的书写顺序大相径庭。
Nginx 变量漫谈(八)的更多相关文章
-
Nginx 变量漫谈(七)
在 (一) 中我们提到过,Nginx 变量的值只有一种类型,那就是字符串,但是变量也有可能压根就不存在有意义的值.没有值的变量也有两种特殊的值:一种是“不合法”(invalid),另一种是“没找到”( ...
-
Nginx 变量漫谈(五)
前面在 (二) 中我们已经了解到变量值容器的生命期是与请求绑定的,但是我当时有意避开了“请求”的正式定义.大家应当一直默认这里的“请求”都是指客户端发起的 HTTP 请求.其实在 Nginx 世界里有 ...
-
Nginx 变量漫谈(四)
在设置了“取处理程序”的情况下,Nginx 变量也可以选择将其值容器用作缓存,这样在多次读取变量的时候,就只需要调用“取处理程序”计算一次.我们下面就来看一个这样的例子: map $args ...
-
Nginx 变量漫谈(三)
也有一些内建变量是支持改写的,其中一个例子是 $args. 这个变量在读取时返回当前请求的 URL 参数串(即请求 URL 中问号后面的部分,如果有的话 ),而在赋值时可以直接修改参数串.我们来看一个 ...
-
Nginx 变量漫谈(二)
关于 Nginx 变量的另一个常见误区是认为变量容器的生命期,是与 location 配置块绑定的.其实不然.我们来看一个涉及“内部跳转”的例子: server { listen ...
-
Nginx 变量漫谈(一)
Nginx 的配置文件使用的就是一门微型的编程语言,许多真实世界里的 Nginx 配置文件其实就是一个一个的小程序.当然,是不是“图灵完全的”暂且不论,至少据我观察,它在设计上受 Perl 和 Bou ...
-
Nginx 变量漫谈
转自:http://blog.sina.com.cn/openrestyNginx 的配置文件使用的就是一门微型的编程语言,许多真实世界里的 Nginx 配置文件其实就是一个一个的小程序.当然,是不是 ...
-
Nginx 变量漫谈(六)
Nginx 内建变量用在“子请求”的上下文中时,其行为也会变得有些微妙. 前面在 (三) 中我们已经知道,许多内建变量都不是简单的“存放值的容器”,它们一般会通过注册“存取处理程序”来表现得与众不同, ...
-
Alink漫谈(八) : 二分类评估 AUC、K-S、PRC、Precision、Recall、LiftChart 如何实现
Alink漫谈(八) : 二分类评估 AUC.K-S.PRC.Precision.Recall.LiftChart 如何实现 目录 Alink漫谈(八) : 二分类评估 AUC.K-S.PRC.Pre ...
随机推荐
-
spfa(模板)
spfa作为图论中的常用算法,深受各类出题人和各位OIer的喜爱: so,为了给大众创造福利,宝宝在此奉上spfa大发的思路和模板:以感谢社会, 感谢CCF,感谢CCTV, 感谢我的老师,感谢同学们, ...
-
Foundation和CoreFoundation之间的转换
Foundation是OC的东西,CoreFoundation是C语言的东西 eg: NSString\NSArray\NSDictionary 属于Foundation CFStringRef\CF ...
-
Android(java)学习笔记70:同步中的死锁问题以及线程通信问题
1. 同步弊端: (1)效率低 (2)如果出现了同步嵌套,就容易产生死锁问题 死锁问题及其代码 : (1)是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象 (2)同步代码块的 ...
-
恢复被误操作删除的数据 fn_dblog
-- Script Name: Recover_Deleted_Data_Proc -- Script Type : Recovery Procedure -- Develop By: Muhamm ...
-
使用Class.getResource和ClassLoader.getResource方法获取文件路径
自从转投Java阵营后,一直发下Java程序的路径读取异常麻烦,因此查阅了比较多的版本内容,整合了一份自己的学习笔记.主要使用Class及通过ClassLoader来动态获取文件路径. 查阅链接如下: ...
-
Mac os 进行Android开发笔记(1)
1> MAC OS Android环境搭建: 2>MAC OS 配置 Andoid ADB: 3>MAC OS 上进行Android真机调试: Android 开发环境搭建: 点击 ...
-
python学习笔记之运算符
目录 前言 软件环境 身份运算符 算术运算符 比较运算符 位移运算符 自变运算符 位运算符 逻辑运算符 成员关系运算符 Python真值表 最后 前言 在前面的博文介绍了Python的数据结构之后,接 ...
-
NOIP经典基础模板总结
date: 20180820 spj: 距离NOIP还有81天 目录 STL模板: priority_queue 的用法:重载<,struct cmpqueue 的用法 stack 的用法vec ...
-
Android Studio 调用夜神模拟器
操作系统:Windows 10 x64 IDE:Android Studio 3.3 夜神模拟器 首先,启动夜神模拟器.快捷键WIN + R打开运行窗口,输入cmd,启动cmd.exe. 使用cd命令 ...
-
进阶之路(基础篇) - 022 Arduino Leonardo 中文介绍(摘抄)
本文摘抄:http://www.arduino.cn/thread-1205-1-1.html 概述Arduino Leonardo是基于ATmega32u4一个微控制器板.它有20个数字输入/输出引 ...