$foo
创建了却未被赋值时,$foo
的值便是“不合法”;而如果当前请求的 URL 参数串中并没有提及XXX
这个参数,则 $arg_XXX 内建变量的值便是“没找到”。
undefined
和 null
这两种特殊值,而 Lua 语言中也有专门的 nil
值: 它们既不等同于空字符串,也不等同于数字0
,更不是布尔值 false
. 其实 SQL 语言中的 NULL
也是类似的一种东西。
location /foo { echo "foo = [$foo]"; } location /bar { set $foo 32; echo "foo = [$foo]"; }
这里为了简单起见,省略了原先写出的外围 server
配置块。在这个例子里,我们在 /bar
接口中用 set 指令隐式地创建了 $foo
变量这个名字,然后我们在 /foo
接口中不对 $foo
进行初始化就直接使用echo 指令输出。我们当时测试/foo
接口的结果是
$ curl 'http://localhost:8080/foo' foo = []
从输出上看,未初始化的 $foo
变量确实和空字符串的效果等同。但细心的读者当时应该就已经注意到,对于上面这个请求,Nginx 的错误日志文件(一般文件名叫做error.log
)中多出一行类似下面这样的警告:
[warn] 5765#0: *1 using uninitialized "foo" variable, ...
这一行警告是谁输出的呢?答案是 set 指令为 $foo
注册的“取处理程序”。当 /foo
接口中的 echo 指令实际执行的时候,它会对它的参数 "foo = [$foo]"
进行“变量插值”计算。于是,参数串中的 $foo
变量会被读取,而 Nginx 会首先检查其值容器里的取值,结果它看到了“不合法”这个特殊值,于是它这才决定继续调用 $foo
变量的“取处理程序”。于是$foo
变量的“取处理程序”开始运行,它向 Nginx 的错误日志打印出上面那条警告消息,然后返回一个空字符串作为 $foo
的值,并从此缓存在$foo
的值容器中。
XXX
并不存在时会返回特殊值“找不到”,但遗憾的是在 Nginx 原生配置语言(我们估且这么称呼它)中是不能很方便地把它和空字符串区分开来的,比如:
location /test { echo "name: [$arg_name]"; }
这里我们输出 $arg_name
变量的值同时故意在请求中不提供 URL 参数 name
:
$ curl 'http://localhost:8080/test' name: []
我们看到,输出特殊值“找不到”的效果和空字符串是相同的。因为这一回是 Nginx 的“变量插值”引擎自动把“找不到”给忽略了。
name
是有值的,而且其值应当是空字符串:
$ curl 'http://localhost:8080/test?name=' name: []
但我们却无法将之和前面完全不提供 name
参数的情况给区分开。
location /test { content_by_lua ' if ngx.var.arg_name == nil then ngx.say("name: missing") else ngx.say("name: [", ngx.var.arg_name, "]") end '; }
这个例子和前一个例子功能上非常接近,除了我们在 /test
接口中使用了 ngx_lua 模块的 content_by_lua 配置指令,嵌入了一小段我们自己的 Lua 代码来对 Nginx 变量 $arg_name
的特殊值进行判断。在这个例子中,当$arg_name
的值为“没找到”(或者“不合法”)时,/foo
接口会输出 name: missing
这一行结果:
curl 'http://localhost:8080/test' name: missing
因为这是我们第一次接触到 ngx_lua 模块,所以需要先简单介绍一下。ngx_lua 模块将 Lua 语言解释器(或者LuaJIT 即时编译器)嵌入到了 Nginx 核心中,从而可以让用户在 Nginx 核心中直接运行 Lua 语言编写的程序。我们可以选择在 Nginx 不同的请求处理阶段插入我们的 Lua 代码。这些 Lua 代码既可以直接内联在 Nginx 配置文件中,也可以单独放置在外部.lua
文件里,然后在 Nginx 配置文件中引用 .lua
文件的路径。
ngx.var
这个由 ngx_lua 模块提供的 Lua 接口。比如引用 Nginx 变量 $VARIABLE
时,就在 Lua 代码里写作 ngx.var.VARIABLE 就可以了。当 Nginx 变量 $arg_name
为特殊值“没找到”(或者“不合法”)时, ngx.var.arg_name
在 Lua 世界中的值就是 nil
,即 Lua 语言里的“空”(不同于 Lua 空字符串)。我们在 Lua 里输出响应体内容的时候,则使用了ngx.say 这个 Lua 函数,也是ngx_lua 模块提供的,功能上等价于ngx_echo 模块的echo 配置指令。
name
参数,则输出就和刚才不相同了:
$ curl 'http://localhost:8080/test?name=' name: []
在这种情况下,Nginx 变量 $arg_name
的取值便是空字符串,这既不是“没找到”,也不是“不合法”,因此在 Lua 里,ngx.var.arg_name
就返回 Lua 空字符串(""),和刚才的 Luanil
值就完全区分开了。
name
这个 URL 参数是否存在来决定是否按name
属性对数据集合进行过滤,而显然提供空字符串作为 name
参数的值,也会导致对数据集中取值为空串的记录进行筛选操作。
/test
接口:
$ curl 'http://localhost:8080/test?name' name: missing
此时,$arg_name
变量仍然读出“找不到”这个特殊值,这就明显有些违反常识。此外,$arg_XXX 变量在请求 URL 中有多个同名XXX
参数时,就只会返回最先出现的那个 XXX
参数的值,而默默忽略掉其他实例:
$ curl 'http://localhost:8080/test?name=Tom&name=Jim&name=Bob' name: [Tom]
要解决这些局限,可以直接在 Lua 代码中使用 ngx_lua 模块提供的 ngx.req.get_uri_args 函数。
此文章由 http://www.ositren.com 收集整理 ,地址为: http://www.ositren.com/htmls/67561.html