https://www.diewufeiyang.com/post/581.html
 

在 (一) 中我们提到过,Nginx 变量的值只有一种类型,那就是字符串,但是变量也有可能压根就不存在有意义的值。没有值的变量也有两种特殊的值:一种是“不合法”(invalid),另一种是“没找到”(not found)。

举例说来,当 Nginx 用户变量 $foo 创建了却未被赋值时,$foo 的值便是“不合法”;而如果当前请求的 URL 参数串中并没有提及 XXX 这个参数,则 $arg_XXX 内建变量的值便是“没找到”。

无论是“不合法”也好,还是“没找到”也罢,这两种 Nginx 变量所拥有的特殊值,和空字符串("")这种取值是完全不同的,比如 JavaScript 语言中也有专门的 undefined 和 null 这两种特殊值,而 Lua 语言中也有专门的 nil 值: 它们既不等同于空字符串,也不等同于数字 0,更不是布尔值 false. 其实 SQL 语言中的 NULL 也是类似的一种东西。

虽然前面在 (一) 中我们看到,由 set 指令创建的变量未初始化就用在“变量插值”中时,效果等同于空字符串,但那是因为 set 指令为它创建的变量自动注册了一个“取处理程序”,将“不合法”的变量值转换为空字符串。为了验证这一点,我们再重新看一下 (一) 中讨论过的那个例子:

Bash
    location /foo {
echo "foo = [$foo]";
} location /bar {
set $foo 32;
echo "foo = [$foo]";
}

这里为了简单起见,省略了原先写出的外围 server 配置块。在这个例子里,我们在 /bar 接口中用 set 指令隐式地创建了 $foo 变量这个名字,然后我们在 /foo 接口中不对 $foo 进行初始化就直接使用 echo 指令输出。我们当时测试 /foo 接口的结果是

Bash
    $ curl 'http://localhost:8080/foo'
foo = []

从输出上看,未初始化的 $foo 变量确实和空字符串的效果等同。但细心的读者当时应该就已经注意到,对于上面这个请求,Nginx 的错误日志文件(一般文件名叫做 error.log)中多出一行类似下面这样的警告:

Bash
    [warn] 5765#0: *1 using uninitialized "foo" variable, ...

这一行警告是谁输出的呢?答案是 set 指令为 $foo 注册的“取处理程序”。当 /foo 接口中的 echo 指令实际执行的时候,它会对它的参数 "foo = [$foo]" 进行“变量插值”计算。于是,参数串中的 $foo 变量会被读取,而 Nginx 会首先检查其值容器里的取值,结果它看到了“不合法”这个特殊值,于是它这才决定继续调用 $foo 变量的“取处理程序”。于是 $foo 变量的“取处理程序”开始运行,它向 Nginx 的错误日志打印出上面那条警告消息,然后返回一个空字符串作为 $foo 的值,并从此缓存在 $foo 的值容器中。

细心的读者会注意到刚刚描述的这个过程其实就是那些支持值缓存的内建变量的工作原理,只不过 set 指令在这里借用了这套机制来处理未正确初始化的 Nginx 变量。值得一提的是,只有“不合法”这个特殊值才会触发 Nginx 调用变量的“取处理程序”,而特殊值“没找到”却不会。

 

上面这样的警告一般会指示出我们的 Nginx 配置中存在变量名拼写错误,抑或是在错误的场合使用了尚未初始化的变量。因为值缓存的存在,这条警告在一个请求的生命期中也不会打印多次。当然,ngx_rewrite 模块专门提供了一条 uninitialized_variable_warn 配置指令可用于禁止这条警告日志。

刚才提到,内建变量 $arg_XXX 在请求 URL 参数 XXX 并不存在时会返回特殊值“找不到”,但遗憾的是在 Nginx 原生配置语言(我们估且这么称呼它)中是不能很方便地把它和空字符串区分开来的,比如:

Bash
    location /test {
echo "name: [$arg_name]";
}

这里我们输出 $arg_name 变量的值同时故意在请求中不提供 URL 参数 name:

Bash
    $ curl 'http://localhost:8080/test'
name: []

我们看到,输出特殊值“找不到”的效果和空字符串是相同的。因为这一回是 Nginx 的“变量插值”引擎自动把“找不到”给忽略了。

那么我们究竟应当如何捕捉到“找不到”这种特殊值的踪影呢?换句话说,我们应当如何把它和空字符串给区分开来呢?显然,下面这个请求中,URL 参数 name 是有值的,而且其值应当是空字符串:

Bash
    $ curl 'http://localhost:8080/test?name='
name: []

但我们却无法将之和前面完全不提供 name 参数的情况给区分开。

幸运的是,通过第三方模块 ngx_lua,我们可以轻松地在 Lua 代码中做到这一点。请看下面这个例子:

Bash
    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 这一行结果:

Bash
    curl 'http://localhost:8080/test'
name: missing

因为这是我们第一次接触到 ngx_lua 模块,所以需要先简单介绍一下。ngx_lua 模块将 Lua 语言解释器(或者 LuaJIT 即时编译器)嵌入到了 Nginx 核心中,从而可以让用户在 Nginx 核心中直接运行 Lua 语言编写的程序。我们可以选择在 Nginx 不同的请求处理阶段插入我们的 Lua 代码。这些 Lua 代码既可以直接内联在 Nginx 配置文件中,也可以单独放置在外部 .lua 文件里,然后在 Nginx 配置文件中引用 .lua 文件的路径。

回到上面这个例子,我们在 Lua 代码里引用 Nginx 变量都是通过 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 参数,则输出就和刚才不相同了:

Bash
    $ curl 'http://localhost:8080/test?name='
name: []

在这种情况下,Nginx 变量 $arg_name 的取值便是空字符串,这既不是“没找到”,也不是“不合法”,因此在 Lua 里,ngx.var.arg_name 就返回 Lua 空字符串(""),和刚才的 Lua nil 值就完全区分开了。

这种区分在有些应用场景下非常重要,比如有的 web service 接口会根据 name 这个 URL 参数是否存在来决定是否按 name 属性对数据集合进行过滤,而显然提供空字符串作为 name 参数的值,也会导致对数据集中取值为空串的记录进行筛选操作。

 

不过,标准的 $arg_XXX 变量还是有一些局限,比如我们用下面这个请求来测试刚才那个 /test 接口:

Bash
    $ curl 'http://localhost:8080/test?name'
name: missing

此时,$arg_name 变量仍然读出“找不到”这个特殊值,这就明显有些违反常识。此外,$arg_XXX 变量在请求 URL 中有多个同名 XXX 参数时,就只会返回最先出现的那个 XXX 参数的值,而默默忽略掉其他实例:

Bash
    $ curl 'http://localhost:8080/test?name=Tom&name=Jim&name=Bob'
name: [Tom]

要解决这些局限,可以直接在 Lua 代码中使用 ngx_lua 模块提供的 ngx.req.get_uri_args 函数。

【转帖】nginx变量使用方法详解-7的更多相关文章

  1. [转帖]Nginx rewrite模块深入浅出详解

    Nginx rewrite模块深入浅出详解 https://www.cnblogs.com/beyang/p/7832460.html rewrite模块(ngx_http_rewrite_modul ...

  2. [转帖]Nginx安装及配置详解 From https://www.cnblogs.com/zhouxinfei/p/7862285.html

    Nginx安装及配置详解   nginx概述 nginx是一款自由的.开源的.高性能的HTTP服务器和反向代理服务器:同时也是一个IMAP.POP3.SMTP代理服务器:nginx可以作为一个HTTP ...

  3. [转帖]nginx服务器安装及配置文件详解

    nginx服务器安装及配置文件详解 http://seanlook.com/2015/05/17/nginx-install-and-config/  发表于 2015-05-17 |  更新于: 2 ...

  4. [转帖]Vim编辑器使用方法详解

    Vim编辑器使用方法详解 程序员小新人学习 2018-12-16 12:26:23 转载于https://www.cnblogs.com/libaoliang/articles/6961676.htm ...

  5. Linux设置和查看环境变量的方法 详解

    1. 显示环境变量HOME $ echo $HOME /home/redbooks 2. 设置一个新的环境变量hello $ export HELLO="Hello!" $ ech ...

  6. Pythony的数据类型和变量使用方法详解

    数据类型:计算机顾名思义就是可以做数学计算的机器,因此,计算机程序理所当然地可以处理各种数值.但是,计算机能处理的远不止数值,还可以处理文本.图形.音频.视频.网页等各种各样的数据,不同的数据,需要定 ...

  7. Nginx服务器中配置非80端口的端口转发方法详解

    这篇文章主要介绍了Nginx服务器中配置非80端口的端口转发方法详解,文中使用到了Nginx中的proxy_pass配置项,需要的朋友可以参考下 nginx可以很方便的配置成反向代理服务器: 1 2 ...

  8. 2-4、nginx特性及基础概念-nginx web服务配置详解

    Nginx Nginx:engine X 调用了libevent:高性能的网络库 epoll():基于事件驱动event的网络库文件 Nginx的特性: 模块化设计.较好扩展性(不支持模块动态装卸载, ...

  9. 【第六课】Nginx常用配置下详解

    目录 Nginx常用配置下详解 1.Nginx虚拟主机 2.部署wordpress开源博客 3.部署discuz开源论坛 4.域名重定向 5.Nginx用户认证 6.Nginx访问日志配置 7.Ngi ...

  10. session的使用方法详解

    session的使用方法详解 Session是什么呢?简单来说就是服务器给客户端的一个编号.当一台WWW服务器运行时,可能有若干个用户浏览正在运正在这台服务器上的网站.当每个用户首次与这台WWW服务器 ...

随机推荐

  1. 在Mac上打开Emoji键盘 ⌨️

    因为想要输入Emoji字符,以前总上到网上搜,如 emojipedia.org ,然后复制.最近,输入Emoji有点多,就想查查有没有什么简便方法. 果然有,我用的是macOS,只要按下键盘上的 co ...

  2. CUDA C编程权威指南:1.2-CUDA基础知识点梳理

      主要整理了N多年前(2013年)学习CUDA的时候开始总结的知识点,好长时间不写CUDA代码了,现在LLM推理需要重新学习CUDA编程,看来出来混迟早要还的. 1.闭扫描和开扫描   对于一个二元 ...

  3. LeetCode 栈与队列篇(12、155、84、239)

    20. 有效的括号 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效. 有效字符串需满足: 左括号必须用相同类型的右括号闭合. 左括号必须以正确的顺序闭合. ...

  4. GaussDB(for Redis)游戏实践:玩家下线行为上报

    本文分享自华为云社区<GaussDB(for Redis) 游戏实践:玩家下线行为上报>,作者:GaussDB 数据库 为保护未成年人的身心健康,2007年国家推出网络游戏防沉迷系统,对未 ...

  5. Volcano:带你体验容器与批量计算的碰撞的火花

    摘要:今年(2020)7月初,Volcano 发布了1.0版本.1.0做为里程碑版本,在Volcano整个规划中起到了承上启下的作用.此次发布的1.0版本支持了GPU共享,作业动态扩缩容,批任务抢占等 ...

  6. 华为云MVP付健权:从机械工程师到AI开发者的华丽转身

    摘要:谁说AI开发难,看一个机械工程师是如何转型成为AI工程师的. 付健权,华为云MVP,企业上云导师.软通动力,售前解决方案经理,为制造业讲解华为云产品,为客户提供上云和云上解决方案.为企业提供大数 ...

  7. 华夏天信携手华为云开天aPaaS,打造安全、高效、节能的主煤流运输系统

    摘要:基于开天aPaaS集成工作台,主煤流运输系统如何实现多源异构数据融合.皮带物料和人员违章的智能感知,以及皮带的智能控制.灵活架构.高效集成.快速开发! 本文分享自华为云社区<华夏天信携手华 ...

  8. 对话 BitSail Contributor | 吴畅:从好奇,到深入

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 2022 年 10 月,字节跳动 BitSail 数据引擎正式开源.同期,社区推出 Contributor 激励计 ...

  9. QA: Solon 怎么输出下载文件流?

    Solon 的Mvc可以直接返回 DownloadedFile 或者 File 对象 @Mapping("/demo/down") @Controller public class ...

  10. Kubernetes(K8S) Controller - Deployment 介绍

    什么是controller 实际存在的,管理和运行容器的对象 Pod 和 Controller 关系 Pod 是通过 Controller 实现应用的运维,比如伸缩.滚动升级等等 Pod 和 Cont ...