子请求
1、ngx.location.capture()
1.1 语法:
1.2 作用域:
rewrite_by_lua*
,access_by_lua*
,content_by_lua*
1.3 options:
- method: 请求方法,默认为
ngx.HTTP_GET
- body: 请求内容,仅限于
string
或nil
- args: 请求参数,支持
string
或table
- vars: 变量,仅限于
table
- ctx: 特殊的
ngx.ctx
变量,可以被当前请求赋值,也可以在子请求使用, 父子请求共享的变量 - copy_all_vars: 复制变量
- always_forward_body:
- 默认是
false
,仅转发put
和post
请求方式中的 body。 - 当设置为
true
时,父请求中的 body 转发到子请求。 - 如果设置 body 选项,则该项设置失效。
- 默认是
- method: 请求方法,默认为
2、
2.1 语法:
-- 同时并发多个请求(各请求相互之间没有依赖关系)
res1, res2, ... = ngx.location.capture_multi({
{uri, options?},
{uri, options?},
...
})
-- 示例
res1, res2, res3 = ngx.location.capture_multi({
{ "/foo", { args = "a=3&b=4" } },
{ "/bar" },
{ "/baz", { method = ngx.HTTP_POST, body = "hello" } },
})
2.2 作用域: 同上
- 2.3 options: 同上
为何如此高效
子请求 只是模拟 HTTP 接口的形式, 没有 额外的 HTTP/TCP 流量,也没有 IPC (进程间通信) 调用。所有工作均在内部、在 C 语言级别高效地完成。
子请求与 HTTP 301/302 重定向指令 (通过 ) 完全不同,也与内部重定向 (通过 ngx.exec) 完全不同,如下表所示:
对请求体的处理
在发起子请求前,用户程序应总是读取完整的 HTTP 请求体 (通过调用 ngx.req.read_body 或设置 指令为 on
)。
子请求的 API 方法 总是缓冲整个请求体到内存中。因此,当需要处理一个大的子请求响应,用户程序应使用 cosockets 进行流式处理,否则内存会被大量消耗,性能急速下降,甚至…。
示例 1、子请求的返回值,例如:
res = ngx.location.capture(uri)
res.status
(状态) :保存子请求的响应状态码。res.header
(头) :用一个标准 Lua 表来存储子请求响应的所有头信息。 如果是“多值”响应头,这些值将使用 Lua 表 (作为数组使用) 顺序存储。例如,如果子请求响应头包含下面的行:则
res.header["Set-Cookie"]
将存储 Lua 表 。res.truncated
(截断):一个布尔值标记。用户需要检测这个布尔值来判断
res.body
是否包含截断的数据。这种数据截断的原因只可能是因为子请求发生了不可恢复的错误,例如远端在发送响应体时 过早中断了连接,或子请求在接收远端响应体时 超时。
示例 2、子请求的 URI,例如:
GET 子请求:URI 请求串可以与 URI 本身连在一起
res = ngx.location.capture('/foo/bar?a=3&b=4')
因为 Nginx 内核限制,子请求不允许类似
@foo
命名 location。请使用标准 location,并设置internal
指令,仅服务内部请求。POST 子请求,可以这样做:
res = ngx.location.capture(
'/foo/bar',
{ method = ngx.HTTP_POST, body = 'hello, world' }
)
示例 3、args 选项,例如:
args
选项可以设置附加的 URI 参数,例如:等同于
ngx.location.capture('/foo?a=1&b=3&c=%3a')
也就是说,这个方法将根据 URI 规则转义参数键和值,并将它们拼接在一起组成一个完整的请求串。
args
选项要求的 Lua 表的格式与 方法中使用的完全相同。args
选项也可以直接包含 (转义过的) 请求串:ngx.location.capture(
'/foo?a=1',
{ args = 'b=3&c=%3a' } }
)
这个例子与上个例子的功能相同。
注意事项
1、 请求头信息
请注意,通过 ngx.location.capture 创建的子请求 默认继承 当前请求的所有请求头信息,这有可能导致子请求响应中不可预测的副作用。
例如,当使用标准的 ngx_proxy
模块服务子请求时,如果主请求头中包含 “Accept-Encoding: gzip”,可能导致子请求返回 Lua 代码无法正确处理的 gzip 压缩过的结果。
解决方案
- 通过设置 proxy_pass_request_headers 为
off
,在子请求 location 中忽略原始请求头; - 在子请求中设置 忽略 Accept-Encoding 头。
2、 无法共同工作的指令
请注意,ngx.location.capture 和 指令无法抓取包含以下指令的 location:
$ curl -i http://example.com/foo
他们将不会按照预期工作。