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
了。这样的结果确实太意外了。