Nginx API for Lua
ngx.arg
ngx.var.VARIABLE
Core constants
HTTP method constants
HTTP status constants
Nginx log level constants
print
ngx.ctx
ngx.location.capture
ngx.location.capture_multi
ngx.status
ngx.header.HEADER
ngx.resp.get_headers
ngx.req.is_internal
ngx.req.start_time
ngx.req.http_version
ngx.req.get_method
ngx.arg
syntax: val = ngx.arg[index]
context: set_by_lua, body_filter_by_lua
location /foo {
set $a 32;
set $b 56;
set_by_lua $sum
'return tonumber(ngx.arg[1]) + tonumber(ngx.arg[2])'
$a $b;
echo $sum;
}
ngx.var.VARIABLE
读写Nginx变量值。
请注意,只能写入已经定义的Nginx变量
syntax: ngx.var.VAR_NAME
context: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua*
value = ngx.var.some_nginx_variable_name
ngx.var.some_nginx_variable_name = value
可以为某些特殊的Nginx变量(例如$ args和$ limit_rate)分配一个值,而其他一些则不能,例如$query_string,$arg_PARAMETER和$http_NAME。
从Nginx变量读取时,Nginx将在每个请求的内存池中分配内存,该内存池仅在请求终止时才释放。 因此,当您需要在Lua代码中重复读取Nginx变量时,请将Nginx变量值缓存到您自己的Lua变量中
上面的意思就是可能会出现内存溢出的情况,这个时候就需要把变量本地化到lua中,就想下面这样。
local val = ngx.var.some_var
--- use the val repeatedly later
Core constants
核心常量
context: init_by_lua, set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua, ngx.timer., balancer_by_lua, ssl_certificate_by_lua, ssl_session_fetch_by_lua, ssl_session_store_by_lua
ngx.OK (0)
ngx.ERROR (-1)
ngx.AGAIN (-2)
ngx.DONE (-4)
ngx.DECLINED (-5)
HTTP method constants
http 方法常量
这些常量通常在ngx.location.capture和ngx.location.capture_multi方法调用中使用。
context: init_by_lua, set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua, ngx.timer., balancer_by_lua, ssl_certificate_by_lua, ssl_session_fetch_by_lua, ssl_session_store_by_lua*
ngx.HTTP_GET
ngx.HTTP_HEAD
ngx.HTTP_PUT
ngx.HTTP_POST
ngx.HTTP_DELETE
ngx.HTTP_OPTIONS (added in the v0.5.0rc24 release)
ngx.HTTP_MKCOL (added in the v0.8.2 release)
ngx.HTTP_COPY (added in the v0.8.2 release)
ngx.HTTP_MOVE (added in the v0.8.2 release)
ngx.HTTP_PROPFIND (added in the v0.8.2 release)
ngx.HTTP_PROPPATCH (added in the v0.8.2 release)
ngx.HTTP_LOCK (added in the v0.8.2 release)
ngx.HTTP_UNLOCK (added in the v0.8.2 release)
ngx.HTTP_PATCH (added in the v0.8.2 release)
ngx.HTTP_TRACE (added in the v0.8.2 release)
HTTP status constants
http 状态常量
context: init_by_lua, set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua, ngx.timer., balancer_by_lua, ssl_certificate_by_lua, ssl_session_fetch_by_lua, ssl_session_store_by_lua*
value = ngx.HTTP_CONTINUE (100) (first added in the v0.9.20 release)
value = ngx.HTTP_SWITCHING_PROTOCOLS (101) (first added in the v0.9.20 release)
value = ngx.HTTP_OK (200)
value = ngx.HTTP_CREATED (201)
value = ngx.HTTP_ACCEPTED (202) (first added in the v0.9.20 release)
value = ngx.HTTP_NO_CONTENT (204) (first added in the v0.9.20 release)
value = ngx.HTTP_PARTIAL_CONTENT (206) (first added in the v0.9.20 release)
value = ngx.HTTP_SPECIAL_RESPONSE (300)
value = ngx.HTTP_MOVED_PERMANENTLY (301)
value = ngx.HTTP_MOVED_TEMPORARILY (302)
value = ngx.HTTP_SEE_OTHER (303)
value = ngx.HTTP_NOT_MODIFIED (304)
value = ngx.HTTP_TEMPORARY_REDIRECT (307) (first added in the v0.9.20 release)
value = ngx.HTTP_PERMANENT_REDIRECT (308)
value = ngx.HTTP_BAD_REQUEST (400)
value = ngx.HTTP_UNAUTHORIZED (401)
value = ngx.HTTP_PAYMENT_REQUIRED (402) (first added in the v0.9.20 release)
value = ngx.HTTP_FORBIDDEN (403)
value = ngx.HTTP_NOT_FOUND (404)
value = ngx.HTTP_NOT_ALLOWED (405)
value = ngx.HTTP_NOT_ACCEPTABLE (406) (first added in the v0.9.20 release)
value = ngx.HTTP_REQUEST_TIMEOUT (408) (first added in the v0.9.20 release)
value = ngx.HTTP_CONFLICT (409) (first added in the v0.9.20 release)
value = ngx.HTTP_GONE (410)
value = ngx.HTTP_UPGRADE_REQUIRED (426) (first added in the v0.9.20 release)
value = ngx.HTTP_TOO_MANY_REQUESTS (429) (first added in the v0.9.20 release)
value = ngx.HTTP_CLOSE (444) (first added in the v0.9.20 release)
value = ngx.HTTP_ILLEGAL (451) (first added in the v0.9.20 release)
value = ngx.HTTP_INTERNAL_SERVER_ERROR (500)
value = ngx.HTTP_METHOD_NOT_IMPLEMENTED (501)
value = ngx.HTTP_BAD_GATEWAY (502) (first added in the v0.9.20 release)
value = ngx.HTTP_SERVICE_UNAVAILABLE (503)
value = ngx.HTTP_GATEWAY_TIMEOUT (504) (first added in the v0.3.1rc38 release)
value = ngx.HTTP_VERSION_NOT_SUPPORTED (505) (first added in the v0.9.20 release)
value = ngx.HTTP_INSUFFICIENT_STORAGE (507) (first added in the v0.9.20 release)
Nginx log level constants
Nginx 错误日志级别
context: init_by_lua, init_worker_by_lua, set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua, ngx.timer., balancer_by_lua, ssl_certificate_by_lua, ssl_session_fetch_by_lua, ssl_session_store_by_lua
ngx.STDERR
ngx.EMERG
ngx.ALERT
ngx.CRIT
ngx.ERR
ngx.WARN
ngx.NOTICE
ngx.INFO
ngx.DEBUG
syntax: print(...)
context: init_by_lua, init_worker_by_lua, set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua, ngx.timer., balancer_by_lua, ssl_certificate_by_lua, ssl_session_fetch_by_lua, ssl_session_store_by_lua
将参数值以ngx.NOTICE日志级别写入Nginx error.log文件。
这个地方可能会写的失败,因为写入的日志级别必须是NOTICE或者是更低的,这个地方是要注意的
等价下面的
ngx.log(ngx.NOTICE, ...)
关于日志
Nginx内核中的错误消息长度有一个硬编码的2048字节限制。 此限制包括尾随换行符和前置时间戳。 如果消息大小超出此限制,Nginx将相应地截断消息文本。 可以通过编辑Nginx源码中src / core / ngx_log.h文件中的NGX_MAX_ERROR_STR宏定义来手动修改此限制
ngx.ctx
该表可用于存储每个请求的Lua上下文数据,并且其生命周期与当前请求相同(与Nginx变量一样)。
context: init_worker_by_lua, set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua, ngx.timer., balancer_by_lua
ngx.ctx.foo在请求的重写,访问和内容阶段持续存在。
location /test {
rewrite_by_lua_block {
ngx.ctx.foo = 76
}
access_by_lua_block {
ngx.ctx.foo = ngx.ctx.foo + 3
}
content_by_lua_block {
ngx.say(ngx.ctx.foo)
}
}
# 输出 79
每个请求(包括子请求)都有自己的表副本。
location /sub {
content_by_lua_block {
ngx.say("sub pre: ", ngx.ctx.blah)
ngx.ctx.blah = 32
ngx.say("sub post: ", ngx.ctx.blah)
}
}
location /main {
content_by_lua_block {
ngx.ctx.blah = 73
ngx.say("main pre: ", ngx.ctx.blah)
local res = ngx.location.capture("/sub")
ngx.print(res.body)
ngx.say("main post: ", ngx.ctx.blah)
}
}
GET /main
main pre: 73
sub pre: nil
sub post: 32
main post: 73
* ngx.location.capture
syntax: res = ngx.location.capture(uri, options?)
context: rewrite_by_lua, access_by_lua, content_by_lua*
使用uri发出同步但仍非阻塞的Nginx子请求。
Nginx的子请求可以向配置了磁盘文件目录或其他任何Nginx C模块(例如ngx_proxy,ngx_fastcgi,ngx_memc,ngx_postgres,ngx_drizzle甚至ngx_lua本身等)的其他位置发出无阻塞内部请求。
子请求仅模仿HTTP接口,但没有额外的HTTP/TCP通信或IPC。一切都在C级别内部有效地进行。
子请求与HTTP301/302重定向(通过ngx.redirect)和内部重定向(通过ngx.exec)完全不同。
在启动子请求之前,必须通过调用ngx.req.read_body或将lua_need_request_body配置为on
此API函数(以及ngx.location.capture_multi)始终在内存中缓冲子请求的整个响应主体。 因此,如果必须处理较大的子请求响应,则应改用cosocket和流处理。
基本用法
res = ngx.location.capture(uri)
返回一个table,包含res.status, res.header, res.body, and res.truncated
res.status:保留子请求响应的响应状态代码。
res.header:包含子请求的所有响应标头,它是一个普通的Lua表。 对于多值响应标头,该值是一个Lua(数组)表,该表按它们出现的顺序保存所有值。
res.body:保留子请求的响应正文数据,该数据可能会被截断。 您始终需要检查res.truncated布尔标志,
以查看res.body是否包含截断的数据。此处的数据截断只能由您的子请求中的那些不可恢复的错误引起,例如在响应主体数据流的中间,远程端过早中止连接,或者当您的子请求从中接收响应主体数据时发生读取超时的情况 遥控器。
增加URI查询字符串的请求
res = ngx.location.capture('/foo/bar?a=3&b=4')
可选的options支持的选项
- method 指定子请求的request方法,该方法仅接受 HTTP status constants (默认值是 ngx.HTTP_GET)
- body 指定子请求的请求主体(仅支持字符串值)
- args 指定子请求的URI查询参数(接受字符串值和Lua table)
- ctx 将Lua表指定为子请求的ngx.ctx表。 它可以是当前请求的ngx.ctx表,可以使当前请求和子请求共享完全相同的上下文表。
- vars 取得一个Lua table,该table保存将子请求中指定的Nginx变量设置为该选项的值的值。
- copy_all_vars 指定是否将当前请求的所有Nginx变量值复制到子请求中。子请求中对Nginx变量的修改不会影响当前请求。
- share_all_vars 指定是否与当前请求共享子请求的所有Nginx变量。子请求中对Nginx变量的修改将影响当前请求。 启用此选项可能会由于不良的副作用而导致难以调试的问题,并且被认为是有害的。仅在完全知道自己在做什么时才启用此选项。
- always_forward_body 如果设置为true,则如果未指定body选项,则当前(父)请求的请求主体将始终转发到正在创建的子请求。 由ngx.req.read_body()或lua_need_request_body读取的请求正文将直接转发到子请求,而无需在创建子请求时复制整个请求正文数据(无论请求正文数据是缓存在内存缓冲区还是临时文件中) 。 默认情况下,此选项为false,并且当未指定body选项时,仅当子请求采用PUT或POST请求方法时才转发当前(父)请求的请求正文。
POST子请求的写法
res = ngx.location.capture(
'/foo/bar',
{ method = ngx.HTTP_POST, body = 'hello, world' }
)
args 参数可以增加额外的参数
// 以下两个请求是等价的
ngx.location.capture('/foo?a=1',
{ args = { b = 3, c = ':' } }
)
ngx.location.capture('/foo?a=1&b=3&c=%3a')
share_all_vars选项控制是否在当前请求及其子请求之间共享Nginx变量。 如果此选项设置为true,则当前请求和关联的子请求将共享相同的Nginx变量范围。 子请求对Nginx变量所做的更改将影响当前请求, 选项的默认值是false。
使用此选项时应格外小心,因为变量范围共享可能会产生意外的副作用。 通常最好使用args,vars或copy_all_vars选项。
location /other {
set $dog "$dog world";
echo "$uri dog: $dog";
}
location /lua {
set $dog 'hello';
content_by_lua_block {
res = ngx.location.capture("/other",
{ share_all_vars = true });
ngx.print(res.body)
ngx.say(ngx.var.uri, ": ", ngx.var.dog)
}
}
# 访问 /lua
/other dog: hello world
/lua: hello world
copy_all_vars选项将父请求的Nginx变量的副本提供给子请求。 此类子请求对这些变量所做的更改不会影响父请求或共享父请求变量的任何其他子请求。
location /other {
set $dog "$dog world";
echo "$uri dog: $dog";
}
location /lua {
set $dog 'hello';
content_by_lua_block {
res = ngx.location.capture("/other",
{ copy_all_vars = true });
ngx.print(res.body)
ngx.say(ngx.var.uri, ": ", ngx.var.dog)
}
}
# 访问 /lua
/other dog: hello world
/lua: hello
如果将share_all_vars和copy_all_vars都设置为true,则share_all_vars优先。
除了上述两个设置之外,还可以使用vars选项为子请求中的变量指定值。 这些变量是检查了变量的共享或复制之后设置的,并提供了一种更有效的方法,即通过将特定值编码为URL参数并将其转义到Nginx配置文件中,将特定值传递给子请求。
location /other {
content_by_lua_block {
ngx.say("dog = ", ngx.var.dog)
ngx.say("cat = ", ngx.var.cat)
}
}
location /lua {
set $dog '';
set $cat '';
content_by_lua_block {
res = ngx.location.capture("/other",
{ vars = { dog = "hello", cat = 32 }});
ngx.print(res.body)
}
}
# /lua
dog = hello
cat = 32
ctx选项可用于指定自定义Lua表,以用作子请求的ngx.ctx表。
location /sub {
content_by_lua_block {
ngx.ctx.foo = "bar";
}
}
location /lua {
content_by_lua_block {
local ctx = {}
res = ngx.location.capture("/sub", { ctx = ctx })
ngx.say(ctx.foo);
ngx.say(ngx.ctx.foo);
}
}
# /lua
bar
nil
也可以使用此ctx选项在当前(父)请求和子请求之间共享相同的ngx.ctx表
location /sub {
content_by_lua_block {
ngx.ctx.foo = "bar";
}
}
location /lua {
content_by_lua_block {
res = ngx.location.capture("/sub", { ctx = ngx.ctx })
ngx.say(ngx.ctx.foo);
}
}
# /lua
bar
ngx.location.capture_multi
syntax: res1, res2, ... = ngx.location.capture_multi({ {uri, options?}, {uri, options?}, ... })
context: rewrite_by_lua, access_by_lua, content_by_lua*
和ngx.location.capture一样,但支持多个并行运行的子请求
此函数发出输入表指定的几个并行子请求,并以相同顺序返回其结果。
res1, res2, res3 = ngx.location.capture_multi{
{ "/foo", { args = "a=3&b=4" } },
{ "/bar" },
{ "/baz", { method = ngx.HTTP_POST, body = "hello" } },
}
if res1.status == ngx.HTTP_OK then
...
end
if res2.body == "BLAH" then
...
end
在所有子请求终止之前,该函数不会返回。总等待时间是各个子请求的最长等待时间,而不是总和。
当事先不知道要发出的子请求数时,Lua表可用于请求和响应
-- construct the requests table
local reqs = {}
table.insert(reqs, { "/mysql" })
table.insert(reqs, { "/postgres" })
table.insert(reqs, { "/redis" })
table.insert(reqs, { "/memcached" })
-- issue all the requests at once and wait until they all return
local resps = { ngx.location.capture_multi(reqs) }
-- loop over the responses table
for i, resp in ipairs(resps) do
-- process the response table "resp"
end
ngx.status
context: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua*
读取和写入当前请求的响应状态。 在发送响应头之前应调用此方法。
ngx.status = ngx.HTTP_CREATED
status = ngx.status
发送响应头后设置ngx.status无效,但会在Nginx的错误日志文件中留下一条错误消息:
attempt to set ngx.status after sending out response headers
ngx.header.HEADER
syntax: ngx.header.HEADER = VALUE
syntax: value = ngx.header.HEADER
context: rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua
设置,添加或清除要发送的当前请求的HEADER响应标头。
默认情况下,标题名称中的下划线(_)将替换为连字符(-)。 可以通过lua_transform_underscores_in_response_headers指令关闭此转换。
标头名称不区分大小写。
-- 相当于 ngx.header["Content-Type"] = 'text/plain'
ngx.header.content_type = 'text/plain';
ngx.header["X-My-Header"] = 'blah blah';
多个值的设置方法
ngx.header['Set-Cookie'] = {'a=32; path=/', 'b=4; path=/'}
产生的效果
Set-Cookie: a=32; path=/
Set-Cookie: b=4; path=/
仅接受Lua表(仅表中的最后一个元素将对仅包含单个值的标准标头(如Content-Type)生效)。
ngx.header.content_type = {'a', 'b'}
# 相当于
ngx.header.content_type = 'b'
删除的方式
ngx.header["X-My-Header"] = nil;
ngx.header["X-My-Header"] = {};
发送响应标头后设置ngx.header.HEADER(显式使用ngx.send_headers或隐式使用ngx.print等)将记录一条错误消息。
读取ngx.header.HEADER将返回名为HEADER的响应标头的值。
标题名称中的下划线(_)也将由短划线(-)替换,并且标题名称将不区分大小写地进行匹配。 如果响应头根本不存在,将返回nil。
这在header_filter_by_lua *的上下文中特别有用
location /test {
set $footer '';
proxy_pass http://some-backend;
header_filter_by_lua_block {
if ngx.header["X-My-Header"] == "blah" then
ngx.var.footer = "some value"
end
}
echo_after_body $footer;
}
请注意,ngx.header不是普通的Lua表,因此,无法使用Lua ipairs函数对其进行迭代。
注意:如果HEADER或VALUE包含不安全的字符(控制字符),则此函数将引发Lua错误。
要读取请求标头,请改用ngx.req.get_headers函数。
ngx.resp.get_headers
syntax: headers, err = ngx.resp.get_headers(max_headers?, raw?)
context: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua, balancer_by_lua
返回一个Lua表,其中包含当前请求的所有当前响应头。
local h, err = ngx.resp.get_headers()
if err == "truncated" then
-- one can choose to ignore or reject the current response here
end
for k, v in pairs(h) do
...
end
函数与ngx.req.get_headers具有相同的签名,除了获取响应标头而不是请求标头。
请注意,默认情况下最多解析100个响应标头(包括具有相同名称的响应标头),并且静默丢弃其他响应标头,以防止潜在的拒绝服务攻击。 从v0.10.13开始,超过限制时,它将返回第二个值,即字符串"truncated"。
ngx.req.is_internal
syntax: is_internal = ngx.req.is_internal()
context: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua*
返回一个布尔值,指示当前请求是否为“内部请求”,即从当前Nginx服务器内部而不是客户端发起的请求。
子请求都是内部请求,内部重定向之后的请求也是如此。
ngx.req.start_time
syntax: secs = ngx.req.start_time()
context: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, log_by_lua*
时间戳
local request_time = ngx.now() - ngx.req.start_time()
ngx.req.http_version
syntax: num = ngx.req.http_version()
context: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua*
以Lua编号的形式返回当前请求的HTTP版本号。
当前可能的值为2.0、1.0、1.1和0.9。 对于无法识别的值,返回nil。
ngx.req.raw_header
syntax: str = ngx.req.raw_header(no_request_line?)
context: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua*
返回Nginx服务器收到的原始原始HTTP协议标头。
默认情况下,还将包括请求行和尾随CR LF终结符。
例如,
ngx.print(ngx.req.raw_header())
GET /t HTTP/1.1
Host: localhost
Connection: close
Foo: bar
您可以将可选的no_request_line参数指定为true值,以将请求行从结果中排除
ngx.print(ngx.req.raw_header(true))
Host: localhost
Connection: close
Foo: bar
ngx.req.get_method
syntax: method_name = ngx.req.get_method()
context: set_by_lua, rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, body_filter_by_lua, balancer_by_lua, log_by_lua
检索当前请求的请求方法名称。 返回诸如“ GET”和“ POST”之类的字符串,而不是数字方法常量。
如果当前请求是Nginx子请求,则将返回子请求的方法名称。