美文网首页
Nginx|nginx变量详解(一)

Nginx|nginx变量详解(一)

作者: 王一百 | 来源:发表于2017-08-16 08:10 被阅读64次

    在nginx配置中,变量只能存放一种类型的值,那就是字符串
    比如在nginx.conf文件有:

    set $a "hello,world";
    
    set $a hello;
    set $b "$a,$a";
    
    • 使用标准ngx_rewrite模块度set配置指令对$a进行了赋值操作
    • 所有的nginx变量在nginx配置文件中被引用时,都要带上$前缀
    • 可以通过已有度nginx变量值来构造一个新的变量的值,称为"变量插值"。比如,上面我们通过已有的变量$a的值来构造变量$b度值。

    一个完整实例

    server {
      listen 8080;
    
      location /test {
      set $foo hello;
      echo "foo: $foo";
      }
    }
    

    使用 curl 这个 HTTP 客
    户端在命令行上请求这个 /test 接口,我们可以得到

    $ curl 'http://localhost:8080/test'
    foo: hello
    

    这里我们使用第三方 ngx_echo 模块的 echo 配置指令将 $foo 变量的值作为当前请求的响应体输出。
    echo指令是支持"变量插值"的。

    geo指令

    如果我们想通过 echo 指令直接输出含有“美元符”($)的字符串,那么有没有办法把特殊的 $ 字符给转义掉呢?答案是否定的。
    但是我们可用通过不支持“变量插值”的模块配置指令专门构造出取值为 $ 的 Nginx 变量,然后再在 echo 中使用这个变量。
    geo指令可以帮我们的忙

    geo $dollar {
      default "$";
    }
    server {
      listen 8080;
      location /test {
      echo "This is a dollar sign: $dollar";
      }
    }
    

    测试结果如下:

    $ curl 'http://localhost:8080/test'
    This is a dollar sign: $
    

    这里用到了标准模块 ngx_geo 提供的配置指令 geo 来为变量 $dollar 赋予字符串 “$”,这样我们在下面需要使用美元符的地方,就直接引用我们的 $dollar 变量就可以了。
    其实 ngx_geo 模块最常规的用法是根据客户端的 IP 地址对指定的 Nginx 变量进行赋值。

    变量插值的歧义问题

    当引用的变量名之后紧跟着变量名的构成字符时(比如后跟字母、数字以及下划线),我们就需要使用特别的记法来消除歧义:

    server {
      listen 8080;
      location /test {
        set $first "hello ";
        echo "${first}world";
      }
    }
    

    我们在 echo 配置指令的参数值中引用变量 $first 的时候,后面紧跟着 world 这个单词,所以如果直接写作 “$firstworld” 则 Nginx “变量插值”计算引擎会将之识别为引用了变量 $firstworld。输出为:

    $ curl 'http://localhost:8080/test
    hello world
    

    如果没有用{}把变量围起来,则会出现无法识别.例如

    server {
      listen 8080;
      location /test {
        set $first "hello ";
        echo "$firstworld";
      }
    }
    

    再重启则出现

    nginx: [emerg] unknown "firstworld" variable
    

    创建变量

    set 指令(以及前面提到的 geo 指令)不仅有赋值的功能,它还有创建Nginx 变量的副作用,即当作为赋值对象的变量尚不存在时,它会自动创建该变量。比如上面的例子中,$a,$b,$first,$dollar等变量在set或geo指令使用前未被创建,直到set指令使用后被创建。如果我们没有创建就直接使用变量,则会无法识别变量。

    server {
      listen 8080;
      location /bad {
        echo $foo;
      }
    }
    

    此时 Nginx 服务器会拒绝加载配置:

    [emerg] unknown "foo" variable
    

    Nginx 变量的创建和赋值操作发生在全然不同的时间阶段。Nginx 变量的创建只能发生在 Nginx 配置加载的时候,或者说 Nginx 启动的时候;而赋值操作则只会发生在请求实际处理的时候。这意味着不创建而直接使用变量会导致启动失败,同时也意味着我们无法在请求处理时动态创建新的 Nginx 变量。

    变量的作用域

    Nginx 变量一旦创建,其变量名的可见范围就是整个 Nginx 配置,甚至可以跨越不同虚拟主机的 server 配置块。

    server {
      listen 8080;
      location /foo {
        echo "foo = [$foo]";
      }
      location /bar {
        set $foo 32;
        echo "foo = [$foo]";
      }
    }
    

    这里我们在 location /bar 中用 set 指令创建了变量 $foo,于是在整个配置文件中这个变量都是可见的,因此我们可以在 location /foo 中直接引用这个变量而不用担心 Nginx 会报错。
    但是,Nginx 变量名的可见范围虽然是整个配置,但每个请求都有所有变量的独立副本,或者说都有各变量用来存放值的容器的独立副本,彼此互不干扰。

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

    set 指令因为是在 location /bar 中使用的,所以赋值操作只会在访问 /bar 的请求中执行。而请求 /foo 接口时,我们总是得到空的 $foo 值,因为用户变量未赋值就输出的话,得到的便是空字符串。
    因此,变量是全局创建,局部使用。也就是变量一旦创建,就在全局中存在,在其他每个请求中都可不创建就直接使用,但是,每个请求中的该变量又是独立的,有独立的值,各自互不影响。

    相关文章

      网友评论

          本文标题:Nginx|nginx变量详解(一)

          本文链接:https://www.haomeiwen.com/subject/oervrxtx.html