location /main { echo "main args: $args"; echo_location /sub "a=1&b=2"; } location /sub { echo "sub args: $args"; }
这里在 /main 接口中,先用 echo 指令输出当前请求的 $args 变量的值,接着再用 echo_location 指令发起子请求 /sub. 这里值得注意的是,我们在 echo_location 语句中除了通过第一个参数指定“子请求”的 URI 之外,还提供了第二个参数,用以指定该“子请求”的 URL 参数串(即 a=1&b=2)。最后我们定义了 /sub 接口,在里面输出了一下 $args 的值。请求 /main 接口的结果如下:
$ curl 'http://localhost:8080/main?c=3' main args: c=3 sub args: a=1&b=2
显然,当 $args 用在“主请求” /main 中时,输出的就是“主请求”的 URL 参数串,c=3;而当用在“子请求”/sub 中时,输出的则是“子请求”的参数串,a=1&b=2。这种行为正符合我们的直觉。
location /main { echo "main uri: $uri"; echo_location /sub; } location /sub { echo "sub uri: $uri"; }
请求 /main 的结果是
$ curl 'http://localhost:8080/main' main uri: /main sub uri: /sub
这依然是我们所期望的。
GET、POST 之类。我们来测试一下:
location /main { echo "main method: $request_method"; echo_location /sub; } location /sub { echo "sub method: $request_method"; }
在这个例子里,/main 和 /sub 接口都会分别输出 $request_method 的值。同时,我们在 /main 接口里利用 echo_location 指令发起一个到 /sub 接口的 GET “子请求”。我们现在利用 curl 命令行工具来发起一个到 /main 接口的 POST 请求:
$ curl --data hello 'http://localhost:8080/main' main method: POST sub method: POST
这里我们利用 curl 程序的 --data 选项,指定 hello 作为我们的请求体数据,同时--data 选项会自动让发送的请求使用 POST 请求方法。测试结果证明了我们先前的预言,$request_method 变量即使在GET “子请求” /sub 中使用,得到的值依然是“主请求” /main 的请求方法,POST.
/sub 子请求。
/main 接口输出 $request_method 变量的时间推迟到“子请求”执行完毕之后:
location /main { echo_location /sub; echo "main method: $request_method"; } location /sub { echo "sub method: $request_method"; }
让我们重新测试一下:
$ curl --data hello 'http://localhost:8080/main' sub method: POST main method: POST
可以看到,再次以 POST 方法请求 /main 接口的结果与原先那个例子完全一致,除了父子请求的输出顺序颠倒了过来(因为我们在本例中交换了/main 接口中那两条输出配置指令的先后次序)。
location /main { echo "main method: $echo_request_method"; echo_location /sub; } location /sub { echo "sub method: $echo_request_method"; }
此时的输出终于是我们想要的了:
$ curl --data hello 'http://localhost:8080/main' main method: POST sub method: GET
我们看到,父子请求分别输出了它们各自不同的请求方法,POST 和 GET.
map $uri $tag { default 0; /main 1; /sub 2; } server { listen 8080; location /main { auth_request /sub; echo "main tag: $tag"; } location /sub { echo "sub tag: $tag"; } }
这里我们使用久违了的 map 指令来把内建变量 $uri 的值映射到用户变量 $tag 上。当 $uri 的值为 /main 时,则赋予 $tag 值 1,当 $uri 取值 /sub 时,则赋予 $tag 值 2,其他情况都赋 0. 接着,我们在/main 接口中先用 ngx_auth_request 模块的 auth_request 指令发起到 /sub 接口的子请求,然后再输出变量$tag 的值。而在 /sub 接口中,我们直接输出变量 $tag. 猜猜看,如果我们访问接口/main,将会得到什么样的输出呢?
$ curl 'http://localhost:8080/main' main tag: 2
咦?我们不是分明把 /main 这个值映射到 1 上的么?为什么实际输出的是 /sub 映射的结果2 呢?
$tag 变量在“子请求” /sub 中首先被读取,于是在那里计算出了值2(因为 $uri 在那里取值 /sub,而根据 map 映射规则,$tag 应当取值 2),从此就被 $tag 的值容器给缓存住了。而auth_request 发起的“子请求”又是与“父请求”共享一套变量的,于是当 Nginx 的执行流回到“父请求”输出 $tag 变量的值时,Nginx 就直接返回缓存住的结果2 了。这样的结果确实太意外了。