nginx 变量

Posted on May 12, 2013

###定义和类型

  • 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 ngx.exec)(有去无回所有只能一次)仍然是一次请求,(容器)变量生命周期延续. Nginx 变量值容器的生命期是与当前正在处理的请求绑定的,而与 location 无关。

    有去无回, 共享变量

    内部跳转后的请求, 还是一个主请求

  • proxy_pass 中容器变量值不会延续, 非内部跳转

    其实这是一个真是请求的发起

    非容器变量如$args可以影响proxy_pass的参数

  • 子请求(如echo_location ngx.location.capture)和父请求都有所有变量值容器的独立副本,有去有回的子请求如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;
    

参考资料