-
序
- 入门篇
- Lua 入门
-
Nginx
-
Nginx 新手起步
-
location 匹配规则
-
静态文件服务
-
日志
-
反向代理
-
负载均衡
-
陷阱和常见错误
- 环境搭建
-
Hello World
-
与其他 location 配合
-
获取 uri 参数
-
获取请求 body
-
输出响应体
-
日志输出
-
简单API Server框架
-
使用 Nginx 内置绑定变量
-
子查询
-
不同阶段共享变量
-
防止 SQL 注入
-
如何发起新 HTTP 请求
-
访问有授权验证的 Redis
-
select+set_keepalive 组合操作引起的数据读写错误
-
redis 接口的二次封装(简化建连、拆连等细节)
-
redis 接口的二次封装(发布订阅)
-
pipeline 压缩请求数量
-
script 压缩复杂请求
-
动态生成的 lua-resty-redis 模块方法
-
Nginx 新手起步
- LuaCjsonLibrary
- PostgresNginxModule
- LuaNginxModule
- LuaRestyDNSLibrary
- LuaRestyLock
- 测试
- Web 服务
- 火焰图
子查询
Nginx 子请求是一种非常强有力的方式,它可以发起非阻塞的内部请求访问目标 location。目标 location 可以是配置文件中其他文件目录,或 任何 其他 nginx C 模块,包括 ngx_proxy
、ngx_fastcgi
、ngx_memc
、ngx_postgres
、ngx_drizzle
,甚至 ngx_lua 自身等等 。
需要注意的是,子请求只是模拟 HTTP 接口的形式, 没有 额外的 HTTP/TCP 流量,也 没有 IPC (进程间通信) 调用。所有工作在内部高效地在 C 语言级别完成。
子请求与 HTTP 301/302 重定向指令 (通过 ngx.redirect) 完全不同,也与内部重定向 ((通过 ngx.exec) 完全不同。
在发起子请求前,用户程序应总是读取完整的 HTTP 请求体 (通过调用 ngx.req.read_body 或设置 lua_need_request_body 指令为 on).
该 API 方法(ngx.location.capture_multi 也一样)总是缓冲整个请求体到内存中。因此,当需要处理一个大的子请求响应,用户程序应使用 cosockets 进行流式处理,
下面是一个简单例子:
res = ngx.location.capture(uri)
copy
返回一个包含四个元素的 Lua 表 (res.status
, res.header
, res.body
, 和 res.truncated
)。
res.status
(状态) 保存子请求的响应状态码。
res.header
(头) 用一个标准 Lua 表储子请求响应的所有头信息。如果是“多值”响应头,这些值将使用 Lua (数组) 表顺序存储。例如,如果子请求响应头包含下面的行:
Set-Cookie: a=3 Set-Cookie: foo=bar Set-Cookie: baz=blah
copy
则 res.header["Set-Cookie"]
将存储 Lua 表 {"a=3", "foo=bar", "baz=blah"}
。
res.body
(体) 保存子请求的响应体数据,它可能被截断。用户需要检测 res.truncated
(截断) 布尔值标记来判断 res.body
是否包含截断的数据。这种数据截断的原因只可能是因为子请求发生了不可恢复的错误,例如远端在发送响应体时过早中断了连接,或子请求在接收远端响应体时超时。
URI 请求串可以与 URI 本身连在一起,例如,
res = ngx.location.capture('/foo/bar?a=3&b=4')
copy
因为 Nginx 内核限制,子请求不允许类似 @foo
命名 location。请使用标准 location,并设置 internal
指令,仅服务内部请求。
例如,发送一个 POST 子请求,可以这样做:
res = ngx.location.capture(
'/foo/bar',
{ method = ngx.HTTP_POST, body = 'hello, world' }
)
copy
除了 POST 的其他 HTTP 请求方法请参考 HTTP method constants。
method
选项默认值是 ngx.HTTP_GET
。
args
选项可以设置附加的 URI 参数,例如:
ngx.location.capture('/foo?a=1',
{ args = { b = 3, c = ':' } }
)
copy
等同于
ngx.location.capture('/foo?a=1&b=3&c=%3a')
copy
也就是说,这个方法将根据 URI 规则转义参数键和值,并将它们拼接在一起组成一个完整的请求串。args
选项要求的 Lua 表的格式与 ngx.encode_args 方法中使用的完全相同。
args
选项也可以直接包含 (转义过的) 请求串:
ngx.location.capture('/foo?a=1',
{ args = 'b=3&c=%3a' } }
)
copy
这个例子与上个例子的功能相同。
请注意,通过 ngx.location.capture 创建的子请求默认继承当前请求的所有请求头信息,这有可能导致子请求响应中不可预测的副作用。例如,当使用标准的 ngx_proxy
模块服务子请求时,如果主请求头中包含 "Accept-Encoding: gzip",可能导致子请求返回 Lua 代码无法正确处理的 gzip 压缩过的结果。通过设置 proxy_pass_request_headers 为 off
,在子请求 location 中忽略原始请求头;或在子请求中设置 proxy_set_header Accept-Encoding "";
忽略 Accept-Encoding 头。
注:ngx.location.capture 和 ngx.location.capture_multi 指令无法抓取包含以下指令的 location: add_before_body, add_after_body, auth_request, echo_location, echo_location_async, echo_subrequest, 或 echo_subrequest_async 。
location /foo {
content_by_lua_block {
res = ngx.location.capture("/bar")
}
}
location /bar {
echo_location /blah;
}
location /blah {
echo "Success!";
}
copy
$ curl -i http://example.com/foo
copy
他们将不会按照预期工作。