Nginx 变量漫谈(二)

关于 Nginx 变量的另一个常见误区是认为变量容器的生命期,是与 location 配置块绑定的。其实不然。我们来看一个涉及“内部跳转”的例子:

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

这里我们在 location /foo 中,使用第三方模块 ngx_echo 提供的 echo_exec 配置指令,发起到 location /bar 的“内部跳转”。所谓“内部跳转”,就是在处理请求的过程中,于服务器内部,从一个 location 跳转到另一个 location 的过程。这不同于利用 HTTP 状态码 301 和 302 所进行的“外部跳转”,因为后者是由 HTTP 客户端配合进行跳转的,而且在客户端,用户可以通过浏览器地址栏这样的界面,看到请求的 URL 地址发生了变化。内部跳转和 Bourne Shell(或 Bash)中的 exec 命令很像,都是“有去无回”。另一个相近的例子是 C 语言中的 goto 语句。

 

    既然是内部跳转,当前正在处理的请求就还是原来那个,只是当前的 location 发生了变化,所以还是原来的那一套 Nginx 变量的容器副本。对应到上例,如果我们请求的是 /foo 这个接口,那么整个工作流程是这样的:先在 location /foo 中通过 set 指令将 $a 变量的值赋为字符串 hello,然后通过 echo_exec 指令发起内部跳转,又进入到 location /bar 中,再输出 $a 变量的值。因为 $a 还是原来的 $a,所以我们可以期望得到 hello 这行输出。测试证实了这一点:

    $ curl localhost:8080/foo    a = [hello]

但如果我们从客户端直接访问 /bar 接口,就会得到空的 $a 变量的值,因为它依赖于 location /foo 来对 $a进行初始化。

 

    从上面这个例子我们看到,一个请求在其处理过程中,即使经历多个不同的 location 配置块,它使用的还是同一套 Nginx 变量的副本。这里,我们也首次涉及到了“内部跳转”这个概念。值得一提的是,标准ngx_rewrite 模块的 rewrite 配置指令其实也可以发起“内部跳转”,例如上面那个例子用 rewrite 配置指令可以改写成下面这样的形式:

    server {        listen 8080;         location /foo {            set $a hello;            rewrite ^ /bar;        }         location /bar {            echo "a = [$a]";        }    }

其效果和使用 echo_exec 是完全相同的。后面我们还会专门介绍这个 rewrite 指令的更多用法,比如发起 301和 302 这样的“外部跳转”。

 

    从上面这个例子我们看到,Nginx 变量值容器的生命期是与当前正在处理的请求绑定的,而与 location 无关。

 

    前面我们接触到的都是通过 set 指令隐式创建的 Nginx 变量。这些变量我们一般称为“用户自定义变量”,或者更简单一些,“用户变量”。既然有“用户自定义变量”,自然也就有由 Nginx 核心和各个 Nginx 模块提供的“预定义变量”,或者说“内建变量”(builtin variables)。

 

    Nginx 内建变量最常见的用途就是获取关于请求或响应的各种信息。例如由 ngx_http_core 模块提供的内建变量 $uri,可以用来获取当前请求的 URI(经过解码,并且不含请求参数),而 $request_uri 则用来获取请求最原始的 URI (未经解码,并且包含请求参数)。请看下面这个例子:

    location /test {        echo "uri = $uri";        echo "request_uri = $request_uri";    }

这里为了简单起见,连 server 配置块也省略了,和前面所有示例一样,我们监听的依然是 8080 端口。在这个例子里,我们把 $uri 和 $request_uri 的值输出到响应体中去。下面我们用不同的请求来测试一下这个 /test接口:

    $ curl 'http://localhost:8080/test'    uri = /test    request_uri = /test     $ curl 'http://localhost:8080/test?a=3&b=4'    uri = /test    request_uri = /test?a=3&b=4     $ curl 'http://localhost:8080/test/hello%20world?a=3&b=4'    uri = /test/hello world    request_uri = /test/hello%20world?a=3&b=4

另一个特别常用的内建变量其实并不是单独一个变量,而是有无限多变种的一群变量,即名字以 arg_ 开头的所有变量,我们估且称之为 $arg_XXX 变量群。一个例子是 $arg_name,这个变量的值是当前请求名为 name 的 URI 参数的值,而且还是未解码的原始形式的值。我们来看一个比较完整的示例:

    location /test {        echo "name: $arg_name";        echo "class: $arg_class";    }

然后在命令行上使用各种参数组合去请求这个 /test 接口:

    $ curl 'http://localhost:8080/test'    name:     class:      $ curl 'http://localhost:8080/test?name=Tom&class=3'    name: Tom    class: 3     $ curl 'http://localhost:8080/test?name=hello%20world&class=9'    name: hello%20world    class: 9

其实 $arg_name 不仅可以匹配 name 参数,也可以匹配 NAME 参数,抑或是 Name,等等:

    $ curl 'http://localhost:8080/test?NAME=Marry'    name: Marry    class:      $ curl 'http://localhost:8080/test?Name=Jimmy'    name: Jimmy    class:

Nginx 会在匹配参数名之前,自动把原始请求中的参数名调整为全部小写的形式。

 

    如果你想对 URI 参数值中的 %XX 这样的编码序列进行解码,可以使用第三方 ngx_set_misc 模块提供的set_unescape_uri 配置指令:

    location /test {        set_unescape_uri $name $arg_name;        set_unescape_uri $class $arg_class;         echo "name: $name";        echo "class: $class";    }

现在我们再看一下效果:

    $ curl 'http://localhost:8080/test?name=hello%20world&class=9'    name: hello world    class: 9

空格果然被解码出来了!

 

    从这个例子我们同时可以看到,这个 set_unescape_uri 指令也像 set 指令那样,拥有自动创建 Nginx 变量的功能。后面我们还会专门介绍到 ngx_set_misc 模块。

 

    像 $arg_XXX 这种类型的变量拥有无穷无尽种可能的名字,所以它们并不对应任何存放值的容器。而且这种变量在 Nginx 核心中是经过特别处理的,第三方 Nginx 模块是不能提供这样充满魔法的内建变量的。

 

    类似 $arg_XXX 的内建变量还有不少,比如用来取 cookie 值的 $cookie_XXX 变量群,用来取请求头的$http_XXX 变量群,以及用来取响应头的 $sent_http_XXX 变量群。这里就不一一介绍了,感兴趣的读者可以参考 ngx_http_core 模块的官方文档。

 

    需要指出的是,许多内建变量都是只读的,比如我们刚才介绍的 $uri 和 $request_uri. 对只读变量进行赋值是应当绝对避免的,因为会有意想不到的后果,比如:

    ? location /bad {    ?     set $uri /blah;    ?     echo $uri;    ? }

这个有问题的配置会让 Nginx 在启动的时候报出一条令人匪夷所思的错误:

    [emerg] the duplicate "uri" variable in ...

如果你尝试改写另外一些只读的内建变量,比如 $arg_XXX 变量,在某些 Nginx 的版本中甚至可能导致进程崩溃。

时间: 2024-10-21 08:07:46

Nginx 变量漫谈(二)的相关文章

Nginx 变量漫谈(三)

也有一些内建变量是支持改写的,其中一个例子是 $args. 这个变量在读取时返回当前请求的 URL 参数串(即请求 URL 中问号后面的部分,如果有的话 ),而在赋值时可以直接修改参数串.我们来看一个例子:     location /test {        set $orig_args $args;        set $args "a=3&b=4";         echo "original args: $orig_args";        

Nginx 变量漫谈(八)

与 $arg_XXX 类似,我们在 (二) 中提到过的内建变量 $cookie_XXX 变量也会在名为 XXX 的 cookie 不存在时返回特殊值"没找到":     location /test {        content_by_lua '            if ngx.var.cookie_user == nil then                ngx.say("cookie user: missing")            else 

Nginx 变量漫谈(四)

在设置了"取处理程序"的情况下,Nginx 变量也可以选择将其值容器用作缓存,这样在多次读取变量的时候,就只需要调用"取处理程序"计算一次.我们下面就来看一个这样的例子:     map $args $foo {        default     0;        debug       1;    }     server {        listen 8080;         location /test {            set $orig_

Nginx 变量漫谈(七)

 在 (一) 中我们提到过,Nginx 变量的值只有一种类型,那就是字符串,但是变量也有可能压根就不存在有意义的值.没有值的变量也有两种特殊的值:一种是"不合法"(invalid),另一种是"没找到"(not found).       举例说来,当 Nginx 用户变量 $foo 创建了却未被赋值时,$foo 的值便是"不合法":而如果当前请求的 URL 参数串中并没有提及 XXX 这个参数,则 $arg_XXX 内建变量的值便是"没

Nginx 变量漫谈(一)

Nginx 的配置文件使用的就是一门微型的编程语言,许多真实世界里的 Nginx 配置文件其实就是一个一个的小程序.当然,是不是"图灵完全的"暂且不论,至少据我观察,它在设计上受 Perl 和 Bourne Shell 这两种语言的影响很大.在这一点上,相比 Apache 和 Lighttpd 等其他 Web 服务器的配置记法,不能不说算是 Nginx 的一大特色了.既然是编程语言,一般也就少不了"变量"这种东西(当然,Haskell 这样奇怪的函数式语言除外了).

nginx变量机制

初识变量 前面曾讲过nginx配置文件的解析过程,也就是nginx如何在启动的过程中对用户设定的配置文件进行解析,并将配置文件中的各个配置项与配置值转换为对应的nginx内部变量值,从而能让nginx按照用户预想的情况去运行. 如果只是一些比较简单并且确定的功能配置需求,那么nginx用户能够很方便的做出相应的设定,比如用户想要设置工作进程数为2个,那么配置文件中这样写即可:worker_processes 2;:与此同理,nginx也很容易做到按用户的配置要求去执行,比如这里nginx也就只需

关于NGINX变量的一些测试结果

作为NGINX变量,不像正规语言那么正式. 但处理自定义和内部变量时,这些操作,也是少不了的. geo $dollar { default "$"; } server { listen 8080; location /test { set $foo chengang; set $first "hello "; echo "${first}world"; echo "foo: $foo"; echo "this is

Nginx学习笔记二基本配置

1.Nginx的配置文件默认在Nginx程序安装目录的conf二级目录下,主配置文件为nginx.conf.假设您的Nginx安装 在/usr/local/webserver/nginx/目录下,那么默认的主配置文件则为/usr/local/webserver/nginx/nginx.conf.2.Nginx配置参数:(1)user www www 指定使用的用户和用户所在的组(2)worker_processes 8 指定工作衍生进程数(一般等于CPU的总核数或总核数的两倍,如两个四核CPU,

Nginx学习之二-配置项解析及编程实现

在开发功能灵活的Nginx模块时,需要从配置文件中获取特定的信息.不过,我们并不需要再编写一套读取配置的系统,Nginx已经为用户提供了强大的配置项解析机制,同时还支持"-s reload"命令,可以在不重启服务的情况下可使配置生效.   一.Nginx配置文件简介 如果编译安装Nginx时使用默认路径,那么Nginx运行目录是/usr/local/nginx,其配置文件存放目录是/usr/local/nginx/conf/nginx.conf.其内容默认如下: [cpp] view