定义和类型
-
Nginx 变量名前面有一个 $ 符号,这是记法上的要求
-
ngixn变量分为用户自定义变量 和 内建变量(有的只读, 有的可读可写)
-
Nginx 变量的值只有一种类型,那就是字符串,字面量使用单双引号通用(还可以不用引号); 还有两种特殊的值:一种是不合法(invalid 定义了但没赋值),另一种是没找到(not found 如变量群中args_XXX没找到)
-
设置变量
set $var "hello world"
使用set(ngx_rewrite
)指令,变量以$开头,包含空格的变量值需要用引号,$在字符串中无法转义,可使用geo $dollar { default "$"; }
(标准模块ngx_geo
)定义变量,这是因为geo不支持$变量内插 -
有些指令(但不是所有的)支持变量在双引号中内插,如 "$var and hello nginx" 或者 "${var}someother"
-
使用未创建变量会报错
生命周期
-
变量生命周期之创建和赋值 变量的创建和赋值操作发生在全然不同的时间阶段。Nginx 变量的创建只能发生在 Nginx 配置加载的时候,或者说 Nginx 启动的时候;而赋值操作则只会发生在请求实际处理的时候。这意味着不创建而直接使用变量会导致启动失败,同时也意味着我们无法在请求处理时动态地创建新的 Nginx 变量
-
容器变量: 被索引的”(indexed); 内部跳转中有效
-
非容器变量: 未索引的”(non-indexed); Nginx 核心提供的取处理程序”(get handler 可以理解为实时获取)和存处理程序”(set handler)实现, 如args等
-
Nginx 变量的生命期是不可能跨越请求边界的 变量名的可见范围虽然是整个配置,但每个请求都有所有变量的独立副本,或者说都有各变量用来存放值的容器的独立副本,彼此互不干扰
这里的请求边界, 既可以是“主请求”,也可以是“子请求”。即便是父子请求之间,同名变量一般也不会相互干扰。如echo_location发起的子请求, 父子请求独立维护自己的容器变量
不幸的是,一些 Nginx 模块发起的“子请求”却会自动共享其“父请求”的变量值容器,比如第三方模块 ngx_auth_request
-
内部跳转(会再重新执行 rewrite、access、content 等处理阶段)(如指令echo_exec 或 rewrite )(有去无回所有只能一次)仍然是一次请求,(容器)变量生命周期延续. Nginx 变量值容器的生命期是与当前正在处理的请求绑定的,而与 location 无关。
有去无回, 共享变量
-
proxy_pass 中容器变量值不会延续, 非内部跳转
-
子请求和父请求都有所有变量值容器的独立副本,有去有回的子请求如
echo_location
echo_location /sub "a=1&b=2";
-
大部分内建变量都用于当前请求(父请求或者子请求)但是少数内建变量只作用于“主请求”,比如由标准模块
ngx_http_core
提供的内建变量 $request_method
常用内建变量
-
$uri 解码,并且不含请求参数
-
$request_uri 未经解码,并且包含请求参数
-
$remote_addr 字符串形式的客户端 IP 地址
-
$proxy_add_x_forwarded_for变量包含客户端请求头中的"X-Forwarded-For",与
$remote_addr
用逗号分开,如果没有"X-Forwarded-For" 请求头,则$proxy_add_x_forwarded_for等于$remote_addr -
$args 请求的 URL 参数串, 非容器变量, 支持写,对其写会改变变量群
$arg_XXX
, 也影响ngx_proxy。 -
$arg_XXX
变量群 XXX大小写均可, 值是未解码的原始形式的值, 如果需要解码后的参数, 可以使用第三方ngx_set_misc
模块提供的 set_unescape_uri 配置指令 -
$http_XXX(请求头)
$http_XXX
内建变量在读取时会返回当前请求中名为 XXX 的请求头,$http_XXX
变量在匹配请求头时会自动对请求头的名字进行归一化,即将名字的大写字母转换为小写字母,同时把间隔符(-)替换为下划线(_) -
其他变量群,
$cookie_XXX
$sent_http_XXX(响应header)。变量群是非容器的,取的时候调用读取程序。
变量缓存
-
ngx_map 模块的 map(只用在http中) 配置指令,
map $args $foo { default 0; debug 1; }
其中第一个值$args是自变量,$foo是因变量, $foo在首次读取后会被缓存
另外map是惰性求值,用到变量才去map,set是主动求值。
常见模块
-
ngx_rewrite 标准
set $a hello;
rewrite 内部跳转 TODO
-
ngx_echo 第三方
echo
echo_exec 内部跳转, 有去无回, 共享变量
echo_location
串行发起若干子请求, 可以指定改变参数:echo_location /sub "a=1&b=2";
$echo_request_method 在子请求中获得http方式
-
ngx_geo 标准
变量赋值TODO
geo $dollar { default "$"; }
-
ngx_proxy 标准的 HTTP 代理模块
proxy_pass 指令
ngx_proxy 模块在转发 HTTP 请求到远方 HTTP 服务的时候,会自动把当前请求的 URL 参数串也转发到远方
-
ngx_map 标准模块
map $args $foo { default 0; debug 1; }
map 只能在http块中定义, 为用户变量注册“取处理程序”, 并会缓存结果; 取处理程序”只有在该用户变量被实际读取时才会执行(当然,因为缓存的存在,只在请求生命期中的第一次读取中才被执行)
-
ngx_http_core
提供内建变量 $uri 等
$request_method: 总是会得到“主请求”的请求方法,比如 GET、POST 之类, 子请求中无效
-
ngx_set_misc 第三方模块提供
获得解码后的参数:
set_unescape_uri $name $arg_name;
-
ngx_auth_request 第三方
auth_request 父子请求间的变量共享
-
ngx_lua
ngx.var 获得nginx变量如ngx.var.var_name, “没找到”(或者“不合法”)对应nil
ngx.say 功能上等价于 ngx_echo 模块的 echo 配置指令, 函数签名 TODO
在 Lua 里访问未创建的 Nginx 用户变量时,在 Lua 里也会得到 nil 值,而不会像先前的例子那样直接让 Nginx 拒绝加载配置
content_by_lua 不支持参数的“变量插值”功能
-
ngx_array_var 第三方
实现数组操作, 不过用lua更方便
array_split "," $arg_names to=$array; array_map "[$array_it]" $array; array_join " " $array to=$res;
参考资料
- agentzh 的 Nginx 教程 http://agentzh.org/misc/nginx/agentzh-nginx-tutorials-zhcn.html