在 Nginx 中,有两种方式添加自定义的变量:

  • 在配置文件中用 set 指定添加
  • 在自己编写的 C 模块中,调用 ngx_http_add_variable 接口来添加变量

第一种方法较简单,第二种方法有一处需要说明一下。

当调用 ngx_http_add_variable 接口时,如果传入的 flag 参数中 NGX_HTTP_VAR_NOHASH 位被设置了,那么在 lua 代码中使用 ngx.var.XXX 是不能访问到该变量的,得到的值是 nil

在这种情况下,如果现在配置文件中通过set指定一个中间变量,则在lua代码中可以访问到。

例如,某个 C 模块中用带有 NGX_HTTP_VAR_NOHASH 位的 flag 参数调用了 ngx_http_add_variable,创建了变量 A,则如果在 lua 代码中通过 ngx.var.A 只能得到一个 nil 值。

而如果在配置文件中,先调用 set 命令:set $B $A;,那么在 lua 代码中,通过代码 local A2 = ngx.var.B 则可以间接访问到该变量。

翻了一下邮件列表,发现该问题 agentzh 早有解答:

逆雪寒: 通过 ngx.var.fastcgi_script_namenil 。 但 set $fsn $fastcgi_script_name 然后 ngx.var.fsn 就能正常获取了。bug ? 还是我理解问题?

agenzh:

这是 Nginx 标准的 ngx_fastcgi 模块的一个限制。$fastcgi_script_name 这个内建变量是这个 ngx_fastcgi 模块定义的,而且在定义时设置了 NGX_HTTP_VAR_NOHASH 这个标志位,从而阻止了 Perl、Lua 等各种脚本语言在请求时按变量名动态获取这个变量的值。

之所以你使用 set 指令进行过渡就可以工作是因为 set 指令定位 $fastcgi_script_name 这个变量是在配置加载时,而不是请求时。

你可以自己修改 Nginx 源码树中的 src/http/modules/ngx_http_fastcgi_module.c 这个文件,从ngx_http_fastcgi_vars 这个全局数组的初始化定义中把 NGX_HTTP_VAR_NOHASH 这个标志去除。

从 ngx_lua 模块的角度,是没办法绕过 Nginx 核心中的这个限制的。关于类似这样的问题,可以参见下面这个讨论:

http://forum.nginx.org/read.php?29,239402,239402,quote=1