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;
 }

top↑

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

top↑

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)

top↑

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)

top↑

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)

top↑

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

top↑

print

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宏定义来手动修改此限制

top↑

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

top↑

* 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

top↑

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

top↑

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

top↑

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函数。

top↑

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"。

top↑

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服务器内部而不是客户端发起的请求。

子请求都是内部请求,内部重定向之后的请求也是如此。

top↑

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()

top↑

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

top↑

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子请求,则将返回子请求的方法名称。

posted @ 2020-06-27 22:29  骑着蜗牛的蚂蚁  阅读(237)  评论(0编辑  收藏  举报