Kong插件开发工具包

Kong插件开发工具包

插件开发工具包(或称 PDK),是一组 Lua 方法和变量,插件可以使用这些方法和变量实现自己的逻辑,PDK 最初在 Kong 0.14.0 中发布,PDK 保证从1.0.0版本开始向前兼容,截至本版本,PDK 尚未达到1.0.0,然而插件作者可以放心依赖它与请求、响应或核心组件进行安全可靠的交互
用户可以通过全局变量访问插件开发工具包,例如 kong.requestkong.log

kong.version

当前 Kong 节点的版本号,字符串格式
用法:

print(kong.version) -- "0.14.0"

kong.version_num

当前 Kong 节点的版本号,用来做版本比较,整数格式
用法:

if kong.version_num < 13000 then -- 000.130.00 -> 0.13.0
-- no support for Routes & Services
end

kong.pdk_major_version

当前 PDK 的大版本号,整数格式
用法:

if kong.pdk_version_num < 2 then
-- PDK is below version 2
end

kong.pdk_version

当前 PDK 的版本号,字符串格式
用法:

print(kong.pdk_version) -- "1.0.0"

kong.configuration

当前 Kong 节点的配置信息,基于配置文件和环境变量,文件中以逗号分隔的列表此处显示为字符串数组
用法:

print(kong.configuration.prefix) -- "/usr/local/kong"
-- this table is read-only; the following throws an error:
kong.configuration.prefix = "foo"

kong.db

Kong 的 DAO 实例(kong.db 模块),包含对多个实体的访问对象
用法:

kong.db.services:insert()
kong.db.routes:select()

kong.dns

Kong 的 DNS 解析器实例

kong.worker_events

Kong 的 IPC 模块实例,用于内部 worker 进程通信

kong.cluster_events

Kong 的集群事件模块实例,用于节点间通信

kong.cache

Kong 缓存对象实例

kong.client

Client 模块是一组方法,通过请求上下文,用于检索连接到Kong的客户端的信息

kong.client.get_ip()

返回发起请求的远程 IP 地址,它将始终返回直连到 Kong 的客户端的地址,所以,当 Kong 之前有负载均衡器的情况下,这个方法会返回负载均衡器的地址,而不是下游客户端的地址

  • 段:
certificate, rewrite, access, header_filter, body_filter, log
  • 返回值:
    发起请求的远程 IP 地址,字符串格式
  • 用法:
-- Given a client with IP 127.0.0.1 making connection through
-- a load balancer with IP 10.0.0.1 to Kong answering the request for
-- https://example.com:1234/v1/movies
kong.client.get_ip() -- "10.0.0.1"

kong.client.get_forwarded_ip()

返回发起请求的远程 IP 地址,与 kong.client.get_ip 不同,这个方法会考虑到位于 Kong 之前的负载均衡器以及转发地址,这个方法是否返回转发地址取决于几个 Kong 配置参数:trusted_ips、real_ip_header、real_ip_recursive

  • 段:
certificate, rewrite, access, header_filter, body_filter, log
  • 返回值:
    发起请求的远程 IP 地址,考虑转发地址,字符串格式
  • 用法:
-- Given a client with IP 127.0.0.1 making connection through
-- a load balancer with IP 10.0.0.1 to Kong answering the request for
-- https://username:password@example.com:1234/v1/movies

kong.request.get_forwarded_ip() -- "127.0.0.1"

-- Note: assuming that 10.0.0.1 is one of the trusted IPs, and that
-- the load balancer adds the right headers matching with the configuration
-- of `real_ip_header`, e.g. `proxy_protocol`.

kong.client.get_port()

返回发起请求的端口,它将始终返回直连到 Kong 的客户端的端口,所以,当 Kong 之前有负载均衡器的情况下,这个方法会返回负载均衡器的端口,而不是下游客户端的端口

  • 段:
certificate, rewrite, access, header_filter, body_filter, log
  • 返回值:
    客户端端口号,整数格式
  • 用法:
-- [client]:40000 <-> 80:[balancer]:30000 <-> 80:[kong]:20000 <-> 80:[service]
kong.client.get_port() -- 30000

kong.client.get_forwarded_port()

返回发起请求的端口,与 kong.client.get_port 不同,这个方法会考虑到位于 Kong 之前的负载均衡器以及转发端口,这个方法是否返回转发端口取决于几个 Kong 配置参数:trusted_ips、real_ip_header、real_ip_recursive

  • 段:
certificate, rewrite, access, header_filter, body_filter, log
  • 返回值:
    客户端端口号,考虑转发端口号,整数格式
  • 用法:
-- [client]:40000 <-> 80:[balancer]:30000 <-> 80:[kong]:20000 <-> 80:[service]
kong.client.get_forwarded_port() -- 40000

-- Note: assuming that [balancer] is one of the trusted IPs, and that
-- the load balancer adds the right headers matching with the configuration
-- of `real_ip_header`, e.g. `proxy_protocol`.

kong.client.get_credential()

返回当前经过身份验证的消费者的凭证,如果未设置,返回 nil

  • 段:
access, header_filter, body_filter, log
  • 返回值:
    经过身份验证的凭证
  • 用法:
local credential = kong.client.get_credential()
if credential then
consumer_id = credential.consumer_id
else
-- request not authenticated yet
end

kong.client.get_consumer()

返回当前经过身份验证的消费者实体,如果未设置,返回 nil

  • 段:
access, header_filter, body_filter, log
  • 返回值:
    经过身份验证的消费者
  • 用法:
local consumer = kong.client.get_consumer()
if consumer then
consumer_id = consumer.id
else
-- request not authenticated yet, or a credential
-- without a consumer (external auth)
end

kong.client.authenticate(consumer, credential)

为当前请求设置经过身份验证的消费者或凭证,消费者和凭证必须存在一个,否则方法将报错

  • 段:
access
  • 参数:
    consumer(table|nil):设置消费者,如果不设置值,之前存在的值会被清空
    credential(table|nil):设置凭证,如果不设置值,之前存在的值会被清空
  • 用法:
-- assuming `credential` and `consumer` have been set by some authentication code
kong.client.authenticate(consumer, credentials)

kong.client.get_protocol(allow_terminated)

返回当前路由匹配的协议,如果没有路由匹配,返回 nil

  • 段:
access, header_filter, body_filter, log
  • 参数:
    allow_terminated:布尔值,如果设置,则在检查 https 时检查 X-Forwarded-Proto
  • 返回值:
  1. string | nil:"http"、"https"、"tcp"、"tls" 或 nil
  2. nil | err:成功返回 nil,失败返回错误信息
  • 用法:
kong.client.get_protocol() -- "http"

kong.ctx

当前请求上下文

kong.ctx.shared

一个 table 结构的数据,它用于在给定请求的多个插件之间共享数据,由于它只与请求的上下文相关,所有无法从 Lua 模块的顶级块访问此表,只能在请求段中访问,对应插件的 rewriteaccessheader_filterbody_filterlog 接口
所有插件都可以看到单个插件在此 table 中插入的值,与其加护时必须谨慎,因为命名冲突会导致数据被覆盖

  • 段:
rewrite, access, header_filter, body_filter, log
  • 用法:
-- Two plugins A and B, and if plugin A has a higher priority than B's
-- (it executes before B):

-- plugin A handler.lua
function plugin_a_handler:access(conf)
kong.ctx.shared.foo = "hello world"

kong.ctx.shared.tab = {
bar = "baz"
}
end

-- plugin B handler.lua
function plugin_b_handler:access(conf)
kong.log(kong.ctx.shared.foo) -- "hello world"
kong.log(kong.ctx.shared.tab.bar) -- "baz"
end

kong.ctx.plugin

一个 table 结构的数据,与 kong.ctx.shared 不同,此 table 不在插件之间共享,相反,它仅对当前插件实例可见,也就是说,如果配置了多个限流插件实例(在不同的服务上),每个实例对于每个请求都有自己的 table
由于它自带命名空间,所以它比 kong.ctx.shared 更安全,因为它避免了潜在的命名冲突,这可能导致多个插件在不知不觉中覆盖了彼此的数据

  • 段:
rewrite, access, header_filter, body_filter, log
  • 用法:
-- plugin handler.lua

function plugin_handler:access(conf)
kong.ctx.plugin.val_1 = "hello"
kong.ctx.plugin.val_2 = "world"
end

function plugin_handler:log(conf)
local value = kong.ctx.plugin.val_1 .. " " .. kong.ctx.plugin.val_2

kong.log(value) -- "hello world"
end

kong.ip

此模块根据 trusted_ips 配置确定给定的 IP 是否可信

kong.ip.is_trusted(address)

根据 trusted_ips 配置属性,此方法将返回给定的 IP 是否可信,并且是否同时支持 ipv4 和 ipv6

  • 段:
init_worker, certificate, rewrite, access, header_filter, body_filter, log
  • 参数:
    address(string):IP 地址
  • 返回值:
    true 代表受信,false代表不受信,布尔格式
  • 用法:
if kong.ip.is_trusted("1.1.1.1") then
kong.log("The IP is trusted")
end

kong.log

一个 table 结构的数据,此命名空间包含了日志工具的实例,含有下述所有方法,每个插件的实例有单独的命名空间,Kong 确保在执行插件之前,会将实例与专用于插件的日志工具交换,这允许日志以插件的名称作为前缀,以便进行调试

kong.log(…)

日志使用当前 Nginx 配置中的 error_log 指令,日志级别是 notice,Nginx 的 error_log 指令通过 log_levelproxy_error_logadmin_error_log 这三个配置设置
传入此方法的参数的拼接方式与 ngx.log() 类似,日志中将显示调用它的 Lua 文件和行号,与 ngx.log() 不同,此方法将使用 [kong],而不是 [lua],作为错误消息的前缀,参数可以是任何格式的,在打印日志时会调用 tostring 方法转换成字符串格式
核心生成的日志格式:

[kong] %file_src:%line_src %message

相比较,插件生成的日志格式:

[kong] %file_src:%line_src [%namespace] %message
  1. %file_src:调用日志的文件名
  2. %func_name:调用日志的方法的名称
  3. %line_src:调用日志的行号
  4. %message:日志消息

示例,调用下列方法:

kong.log("hello ", "world")

核心打印日志:

2017/07/09 19:36:25 [notice] 25932#0: *1 [kong] some_file.lua:54 hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost"

插件打印日志:

2017/07/09 19:36:25 [notice] 25932#0: *1 [kong] some_file.lua:54 [key-auth] hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost"
  • 段:
init_worker, certificate, rewrite, access, header_filter, body_filter, log
  • 参数:
    在发送到日志之前,所有的参数会拼接到一起连成字符串
  • 返回值:
    没有返回,无效的输入抛错
  • 用法:
kong.log("hello ", "world") -- alias to kong.log.notice()

kong.log.LEVEL(…)

kong.log() 类似,但生成的日志具有 \<level\> 日志级别,而不是 notice,支持的日志级别包括:
kong.log.alert()
kong.log.crit()
kong.log.err()
kong.log.warn()
kong.log.notice()
kong.log.info()
kong.log.debug()
记录日志的语法与 kong.log() 类似,例如:

kong.log.err("hello ", "world")

在核心内会生成一条日志,如下:

2017/07/09 19:36:25 [error] 25932#0: *1 [kong] some_file.lua:54 hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost"

如果从插件中调用(例如 key-auth),它将包含命名空间前缀,如下:

2017/07/09 19:36:25 [error] 25932#0: *1 [kong] some_file.lua:54 [key-auth] hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost"
  • 段:
init_worker, certificate, rewrite, access, header_filter, body_filter, log
  • 参数:
    在发送到日志之前,所有的参数会拼接到一起连成字符串
  • 返回值:
    没有返回,无效的输入抛错
  • 用法:
kong.log.warn("something require attention")
kong.log.err("something failed: ", err)
kong.log.alert("something requires immediate action")

kong.log.inspect(…)

kong.log() 类似,此方法会生成 notice 级别的日志,并且可以接受任意数量的参数,如果通过 kong.log.inspect.off() 方法禁用了功能,那么此方法不会打印任何内容

kong.log.inspect("...")

kong.log() 不同的是,该方法会在拼接参数时加上空格,这个方法主要用于调试,应避免在生产代码中使用,因为它执行了很多格式化操作,消耗资源
kong.log.inspect(…) 的日志格式如下:

%file_src:%func_name:%line_src %message
  1. %file_src:调用日志的文件名
  2. %func_name:调用日志的方法的名称
  3. %line_src:调用日志的行号
  4. %message:日志消息
  • 段:
init_worker, certificate, rewrite, access, header_filter, body_filter, log
  • 参数:
    在发送到日志之前,所有的参数会拼接到一起连成字符串
  • 用法:
kong.log.inspect("some value", a_variable)

kong.log.inspect.on()

启用 inspect 日志功能

  • 段:
init_worker, certificate, rewrite, access, header_filter, body_filter, log
  • 用法:
kong.log.inspect.on()

kong.log.inspect.off()

禁用 notice 日志功能

  • 段:
init_worker, certificate, rewrite, access, header_filter, body_filter, log
  • 用法:
kong.log.inspect.off()

kong.nginx

Nginx 信息模块,一组用于检索 Nginx 实现细节和元信息的方法

kong.nginx.get_subsystem()

  • 段:
any
  • 返回值:
    httpstream,字符串格式
  • 用法:
kong.nginx.get_subsystem() -- "http"

kong.node

节点级别信息

kong.node.get_id()

返回此节点用于描述自身的 ID

  • 返回值:
    节点 ID,字符串格式
  • 用法:
local id = kong.node.get_id()

kong.node.get_memory_stats([unit[, scale]])

返回该节点的内存使用数据

  • 参数:
    unit(string, optional):内存计量单位,可以是 b/B、k/K、m/M 或 g/G
    scale(number, optional):精度,默认小数点后两位
  • 返回值:
    包含此节点的内存使用统计数据,如果单位是 b/B(默认值),则值为数字,否则统计数据为字符串,后缀是单位,table 格式
  • 用法:
local res = kong.node.get_memory_stats()
-- res will have the following structure:
{
  lua_shared_dicts = {
    kong = {
      allocated_slabs = 12288,
      capacity = 24576
    },
    kong_db_cache = {
      allocated_slabs = 12288,
      capacity = 12288
    }
  },
  workers_lua_vms = {
    {
      http_allocated_gc = 1102,
      pid = 18004
    },
    {
      http_allocated_gc = 1102,
      pid = 18005
    }
  }
}

local res = kong.node.get_memory_stats("k", 1)
-- res will have the following structure:
{
  lua_shared_dicts = {
    kong = {
      allocated_slabs = "12.0 KiB",
      capacity = "24.0 KiB",
    },
    kong_db_cache = {
      allocated_slabs = "12.0 KiB",
      capacity = "12.0 KiB",
    }
  },
  workers_lua_vms = {
    {
      http_allocated_gc = "1.1 KiB",
      pid = 18004
    },
    {
      http_allocated_gc = "1.1 KiB",
      pid = 18005
    }
  }
}

kong.request

一组方法,用于获取客户端发出的请求信息

kong.request.get_scheme()

返回请求 URL 的 schema 组件,返回值为小写格式

  • 段:
rewrite, access, header_filter, body_filter, log, admin_api
  • 返回值:
    http 或者 https,字符串格式
  • 用法:
-- Given a request to https://example.com:1234/v1/movies
kong.request.get_scheme() -- "https"

kong.request.get_host()

返回请求 URL 的 host 组件,或者 Host 头的值,返回值为小写格式

  • 段:
rewrite, access, header_filter, body_filter, log, admin_api
  • 返回值:
    主机地址,字符串格式
  • 用法:
-- Given a request to https://example.com:1234/v1/movies
kong.request.get_host() -- "example.com"

kong.request.get_port()

返回请求 URL 的 port 组件

  • 段:
certificate, rewrite, access, header_filter, body_filter, log, admin_api
  • 返回值:
    端口号,整数格式
  • 用法:
-- Given a request to https://example.com:1234/v1/movies
kong.request.get_port() -- 1234

kong.request.get_forwarded_scheme()

返回请求 URL 的 schema 组件,如果请求来自可信源,也会考虑 X-Forwarded-Proto 请求头,返回值为小写格式,该方法是否考虑 X-Forwarded-Proto 请求头取决于几个 Kong 配置参数:trusted_ips、real_ip_header、real_ip_recursive

  • 段:
rewrite, access, header_filter, body_filter, log, admin_api
  • 返回值:
    转发的 schema,字符串格式
  • 用法:
kong.request.get_forwarded_scheme()  -- "https"

kong.request.get_forwarded_host()

返回请求 URL 的 host 组件,不同于 kong.request.get_host(),如果请求来自可信源,也会考虑 X-Forwarded-Host 请求头,该方法是否考虑 X-Forwarded-Host 请求头取决于几个 Kong 配置参数:trusted_ips、real_ip_header、real_ip_recursive

  • 段:
rewrite, access, header_filter, body_filter, log, admin_api
  • 返回值:
    转发的主机地址,字符串格式
  • 用法:
kong.request.get_forwarded_host()  -- "example.com"

kong.request.get_forwareded_port()

返回请求 URL 的 port 组件,如果请求来自可信源,也会考虑 X-Forwarded-Host 请求头,该方法是否考虑 X-Forwarded-Proto 请求头取决于几个 Kong 配置参数:trusted_ips、real_ip_header、real_ip_recursive

  • 段:
rewrite, access, header_filter, body_filter, log, admin_api
  • 返回值:
    转发的端口,整数格式
  • 用法:
kong.request.get_forwarded_port()  -- 1234

kong.request.get_http_version()

返回 Http 协议使用的版本号,返回值为 1.12.0

  • 段:
rewrite, access, header_filter, body_filter, log, admin_api
  • 返回值:
    字符串类型,或者是 nil
  • 用法:
kong.request.get_http_version()  -- "1.1"

kong.request.get_method()

返回请求的 Http 方法,返回值为大写格式

  • 段:
rewrite, access, header_filter, body_filter, log, admin_api
  • 返回值:
    请求方法,字符串格式
  • 用法:
kong.request.get_method()  -- "GET"

kong.request.get_path()

返回请求 URL 的 path 组件,不包含请求参数

  • 段:
rewrite, access, header_filter, body_filter, log, admin_api
  • 返回值:
    请求路径,字符串格式
  • 用法:
-- Given a request to https://example.com:1234/v1/movies?movie=foo
kong.request.get_path() -- "/v1/movies"

kong.request.get_path_with_query()

返回请求 URL 的 path 组件,包含请求参数

  • 段:
rewrite, access, header_filter, body_filter, log, admin_api
  • 返回值:
    请求路径,包含请求参数,字符串格式
  • 用法:
-- Given a request to https://example.com:1234/v1/movies?movie=foo
kong.request.get_path_with_query() -- "/v1/movies?movie=foo"

kong.request.get_raw_query()

返回请求 URL 的 query 组件,不包含 ? 字符

  • 段:
rewrite, access, header_filter, body_filter, log, admin_api
  • 返回值:
    请求参数
  • 用法:
-- Given a request to https://example.com/foo?msg=hello%20world&bla=&bar
kong.request.get_raw_query() -- "msg=hello%20world&bla=&bar"

kong.request.get_query_arg()

返回从当前请求的查询参数获取的指定参数的值,如果参数有值,返回的是字符串或者布尔类型,如果找不到参数,返回 nil,如果查询参数中多次出现具有相同名称的参数,该方法返回第一次出现的值

  • 段:
rewrite, access, header_filter, body_filter, log, admin_api
  • 返回值:
    请求参数,字符串类型、布尔类型、nil
  • 用法:
-- Given a request GET /test?foo=hello%20world&bar=baz&zzz&blo=&bar=bla&bar
kong.request.get_query_arg("foo") -- "hello world"
kong.request.get_query_arg("bar") -- "baz"
kong.request.get_query_arg("zzz") -- true
kong.request.get_query_arg("blo") -- ""

kong.request.get_query([max_args])

返回从请求参数提取的参数表,键是参数名称,值是参数值,键和值都未经转义,默认情况下,这个方法返回100个参数,可以指定 max_args 调整这个值,参数范围是1至1000

  • 段:
rewrite, access, header_filter, body_filter, log, admin_api
  • 参数:
    max_args(number, optional):参数表的最大个数
  • 返回值:
    请求参数,table 格式
  • 用法:
-- Given a request GET /test?foo=hello%20world&bar=baz&zzz&blo=&bar=bla&bar
for k, v in pairs(kong.request.get_query()) do
  kong.log.inspect(k, v)
end
-- Will print
-- "foo" "hello world"
-- "bar" {"baz", "bla", true}
-- "zzz" true
-- "blo" ""

kong.request.get_header(name)

返回请求头的值,请求头名不区分大小写,并全部采用小写形式,- 可以写成 _,比如 X-Custom-Header 可以写成 x_custom_header

  • 段:
rewrite, access, header_filter, body_filter, log, admin_api
  • 参数:
    name(string):请求头的名称
  • 返回值:
    请求头的值,字符串类型或者 nil
  • 用法:
-- Given a request with the following headers:
-- Host: foo.com
-- X-Custom-Header: bla
-- X-Another: foo bar
-- X-Another: baz
kong.request.get_header("Host")            -- "foo.com"
kong.request.get_header("x-custom-header") -- "bla"
kong.request.get_header("X-Another")       -- "foo bar"

kong.request.get_headers([max_headers])

返回请求头表,键是请求头名,值是请求头值,默认情况下,这个方法返回100个请求头,可以指定 max_headers 调整这个值,参数范围是1至1000

  • 段:
rewrite, access, header_filter, body_filter, log, admin_api
  • 参数:
    max_headers(number, optional):请求头表的最大个数
  • 返回值:
    请求头,table 格式
  • 用法:
-- Given a request with the following headers:
-- Host: foo.com
-- X-Custom-Header: bla
-- X-Another: foo bar
-- X-Another: baz
local headers = kong.request.get_headers()
headers.host            -- "foo.com"
headers.x_custom_header -- "bla"
headers.x_another[1]    -- "foo bar"
headers["X-Another"][2] -- "baz"

kong.request.get_raw_body()

返回请求体,如果请求体没有内容,该方法返回一个空字符串,如果请求体大小大于 Nginx 缓冲区大小(通过 client_body_buffer_size 设置),该方法会失败并返回错误信息

  • 段:
rewrite, access, admin_api
  • 返回值:
    请求体,字符串格式
  • 用法:
-- Given a body with payload "Hello, Earth!":
kong.request.get_raw_body():gsub("Earth", "Mars") -- "Hello, Mars!"

kong.request.get_body([mimetype[, max_args]])

以键值对形式返回请求体数据,请求体以最合适的格式解析:

  1. 如果指定了 mimetype,根据 content type 对请求体进行解码
  2. 如果 content type 是 application/x-www-form-urlencoded,以 form-encoded 形式返回请求体
  3. 如果 content type 是 multipart/form-data,以上述方式解析,multipart(kong.request.get_raw_body(), kong.request.get_header("Content-Type")):get_all()
  4. 如果 content type 是 application/json,以 JSON 形式解析请求体,JSON 格式对应 Lua 的基本类型
  5. 如果不是上述情况,返回 nil 表示请求未被解析
    mimetype 可以取以下值:application/x-www-form-urlencodedapplication/jsonmultipart/form-data
    max_args 限定 application/x-www-form-urlencoded 解析参数的个数
  • 段:
rewrite, access, admin_api
  • 参数:
    mimetype(string, optional):mimetype
    max_args(number, optional):请求体表的最大个数
  • 返回值:
  1. 请求体,table 格式或 nil
  2. 错误信息,table 格式或 nil
  3. mimetype 类型,table 格式或 nil
  • 用法:
local body, err, mimetype = kong.request.get_body()
body.name -- "John Doe"
body.age  -- "42"

kong.response

响应模块,其中包含了一组方法,用于生成和操作发送发送给客户端的响应,响应可以由 Kong 生成,或者从服务的响应体中代理过来

kong.response.get_status()

返回当前为下游响应设置的的 Http 状态码,如果请求被代理,则返回值将是来自 Service 的响应值(与 kong.service.response.get_status() 相同),如果请求未被代理,并且响应是由 Kong 本身产生的(比如通过 kong.response.exit()),则返回值将按原样返回

  • 段:
header_filter, body_filter, log, admin_api
  • 返回值:
    为下游响应设置的 Http 状态码
  • 用法:
kong.response.get_status()  -- 200

kong.response.get_header(name)

返回指定响应头的值,该函数包含来自代理服务的响应头和 Kong 添加的响应头(例如,通过 kong.response.add_header()

  • 段:
header_filter, body_filter, log, admin_api
  • 参数:
    name(string):请求头的名称,请求头名不区分大小写,并全部采用小写形式,- 可以写成 _,比如 X-Custom-Header 可以写成 x_custom_header
  • 返回值:
    响应头的值,字符串格式或 nil
  • 用法:
-- Given a response with the following headers:
-- X-Custom-Header: bla
-- X-Another: foo bar
-- X-Another: baz

kong.response.get_header("x-custom-header") -- "bla"
kong.response.get_header("X-Another")       -- "foo bar"
kong.response.get_header("X-None")          -- nil

kong.response.get_headers([max_headers])

包含响应头的 Lua table,与 kong.service.response.get_headers() 不同,该方法会返回客户端接收到的所有响应头,包括 Kong 本身添加的响应有,默认情况下,该方法最多返回100个响应头,可以指定 max_headers 调整这个值,参数范围是1至1000

  • 段:
header_filter, body_filter, log, admin_api
  • 参数:
    max_headers(number, optional):
  • 返回值:
  1. 响应中的响应头 table,table 格式
  2. 如果响应头数目超过 max_headers,返回 truncated,字符串格式
  • 用法:
-- Given an response from the Service with the following headers:
-- X-Custom-Header: bla
-- X-Another: foo bar
-- X-Another: baz

local headers = kong.response.get_headers()

headers.x_custom_header -- "bla"
headers.x_another[1]    -- "foo bar"
headers["X-Another"][2] -- "baz"

kong.response.get_source()

这个方法确定当前响应的来源,返回值可能包含三类字符串:

  1. exit:调用了 kong.response.exit(),即请求被插件或 Kong 本身短路的时候
  2. error:发生错误,比如连接到上游服务超时,返回 error
  3. service:连接到代理服务,返回 service
  • 段:
header_filter, body_filter, log, admin_api
  • 返回值:
    响应源,字符串格式
  • 用法:
if kong.response.get_source() == "service" then
  kong.log("The response comes from the Service")
elseif kong.response.get_source() == "error" then
  kong.log("There was an error while processing the request")
elseif kong.response.get_source() == "exit" then
  kong.log("There was an early exit while processing the request")
end

kong.response.set_status(status)

更改 Http 状态码,这个方法应该在 header_filter 段中使用,此时 Kong 准备将响应头发送回客户端

  • 段:
rewrite, access, header_filter, admin_api
  • 参数:
    status(number):新的 Http 状态码
  • 返回值:
    无;无效的输入抛出错误
  • 用法:
kong.response.set_status(404)

kong.response.set_header(name, value)

设置响应头,会覆盖已经存在的响应头,这个方法应该在 header_filter 段中使用,此时 Kong 准备将响应头发送回客户端

  • 段:
rewrite, access, header_filter, admin_api
  • 参数:
    name(string): 响应头的名称
    value(string,number,boolean):响应头的值
  • 返回值:
    无;无效的输入抛出错误
  • 用法:
kong.response.set_header("X-Foo",  "value")

kong.response.add_header(name, value)

设置响应头,与 kong.response.set_header() 不同,这个方法不会覆盖已经存在的响应头,另外相同的响应头可以继续添加在响应中,这个方法应该在 header_filter 段中使用,此时 Kong 准备将响应头发送回客户端

  • 段:
rewrite, access, header_filter, admin_api
  • 参数:
    name(string): 响应头的名称
    value(string,number,boolean):响应头的值
  • 返回值:
    无;无效的输入抛出错误
  • 用法:
kong.response.add_header("Cache-Control", "no-cache")
kong.response.add_header("Cache-Control", "no-store")

kong.response.clear_header(name)

删除响应头,这个方法应该在 header_filter 段中使用,此时 Kong 准备将响应头发送回客户端

  • 段:
rewrite, access, header_filter, admin_api
  • 参数:
    name(string): 需要清除的响应头的名称
  • 返回值:
    无;无效的输入抛出错误
  • 用法:
kong.response.set_header("X-Foo", "foo")
kong.response.add_header("X-Foo", "bar")

kong.response.clear_header("X-Foo")
-- from here onwards, no X-Foo headers will exist in the response

kong.response.set_headers(headers)

设置响应头,与 kong.response.set_header() 不同,headers 参数是一个 table,键是字符串格式,值是字符串或字符串数组,这个方法应该在 header_filter 段中使用,此时 Kong 准备将响应头发送回客户端,此方法会覆盖已经存在的响应头

  • 段:
rewrite, access, header_filter, admin_api
  • 参数:
    headers(table)
  • 返回值:
    无;无效的输入抛出错误
  • 用法:
kong.response.set_headers({
  ["Bla"] = "boo",
  ["X-Foo"] = "foo3",
  ["Cache-Control"] = { "no-store", "no-cache" }
})

-- Will add the following headers to the response, in this order:
-- X-Bar: bar1
-- Bla: boo
-- Cache-Control: no-store
-- Cache-Control: no-cache
-- X-Foo: foo3

kong.response.exit(status[, body[, headers]])

  • 段:
rewrite, access, admin_api, header_filter (仅当 body 为 nil 时)
  • 参数:
  1. status(number):Http 状态码
  2. body(table,string,optional):响应体
  3. headers(table,optional):响应头
  • 返回值:
    无;无效的输入抛出错误
  • 用法:
return kong.response.exit(403, "Access Forbidden", {
  ["Content-Type"] = "text/plain",
  ["WWW-Authenticate"] = "Basic"
})

---

return kong.response.exit(403, [[{"message":"Access Forbidden"}]], {
  ["Content-Type"] = "application/json",
  ["WWW-Authenticate"] = "Basic"
})

---

return kong.response.exit(403, { message = "Access Forbidden" }, {
  ["WWW-Authenticate"] = "Basic"
})

kong.router

route 模块包含一组方法,用于访问请求的路由属性

kong.router.get_route()

返回路由实体,请求与此路由匹配

  • 段:
access, header_filter, body_filter, log
  • 返回值:
    路由实体,table 格式
  • 用法:
if kong.router.get_route() then
  -- routed by route & service entities
else
  -- routed by a legacy API entity
end

kong.router.get_service()

返回当前服务实体,请求会路由到这个服务上

  • 段:
access, header_filter, body_filter, log
  • 返回值:
    服务实体,table 格式
  • 用法:
if kong.router.get_service() then
  -- routed by route & service entities
else
  -- routed by a legacy API entity
end

kong.service

service 模块包含一组方法,用于操作请求连接到服务上的属性,比如连接的主机,IP 地址或端口,用于负载均衡和健康检查的 upstream 实体

kong.service.set_upstream(host)

设置所需的 upstream 实体处理请求的负载均衡,使用此方法相当于创建一个配置了 host 属性的服务,并关联到了相应的 upstream 实体(这种情况下,请求将代理到绑定到这个 upstream 的 target 上)
host 参数接收一个字符串,字符串内容需要与配置的 upstream 实体一致

  • 段:
access
  • 参数:
    host(string)
  • 返回值:
  1. 成功返回 true,没有找到 upstream 实体返回 nil
  2. 错误发生时返回字符串格式的错误,没有返回 nil
  • 用法:
local ok, err = kong.service.set_upstream("service.prod")
if not ok then
  kong.log.err(err)
  return
end

kong.service.set_target(host, port)

设置代理该请求的主机和端口地址,使用这个方法相当于要求 Kong 在接收请求时不执行负载均衡阶段,而是手动覆盖它,这个请求还会忽略重试和健康检查等负载均衡组件,host 参数为字符串格式,是一个(IPv4/IPv6地址),port 参数为端口号

  • 段:
access
  • 参数:
    host(string)
    port(number)
  • 用法:
kong.service.set_target("service.local", 443)
kong.service.set_target("192.168.130.1", 80)

kong.service.set_tls_cert_key(chain, key)

设置与服务器端握手时使用的客户端证书,chain 参数是由 ngx.ssl.parse_pem_cert 等方法返回的客户端证书和中间链,key 参数是与 ngx.ssl.parse_pem_priv_key 等方法返回的客户端证书对应的私钥

  • 段:
rewrite, access, balancer
  • 参数:
    chain(cdata):客户端证书链
    key(cdata):客户端证书私钥
  • 返回值:
  1. 操作成功返回 true,发生错误返回 nil
  2. 错误发生时返回字符串格式的错误,没有返回 nil
  • 用法:
local chain = assert(ssl.parse_pem_cert(cert_data))
local key = assert(ssl.parse_pem_priv_key(key_data))

local ok, err = tls.set_cert_key(chain, key)
if not ok then
  -- do something with error
end

kong.service.request

操作连接上服务的请求

kong.service.request.set_scheme(scheme)

在将请求路由到服务时设置 Http 协议

  • 段:
access
  • 参数:
    schema(string):Http 协议,支持 httphttps
  • 返回值:
    无;无效的输入抛出错误
  • 用法:
kong.service.request.set_scheme("https")

kong.service.request.set_path(path)

设置请求路径,不包含请求参数

  • 段:
access
  • 参数:
    path(string):请求路径
  • 返回值:
    无;无效的输入抛出错误
  • 用法:
kong.service.request.set_path("/v2/movies")

kong.service.request.set_raw_query(query)

设置请求参数,query 参数是字符串格式(不包含 ? 字符),并且不会以任何方式处理,更高阶的设置请求参数方法参考 kong.service.request.set_query()

  • 段:
rewrite,access
  • 参数:
    query(string):原生的请求参数
  • 返回值:
    无;无效的输入抛出错误
  • 用法:
kong.service.request.set_raw_query("zzz&bar=baz&bar=bla&bar&blo=&foo=hello%20world")

kong.service.request.set_method(method)

设置 Http 方法

  • 段:
rewrite,access
  • 参数:
    method(string):Http 方法,需要大小,支持的方法有:GETHEADPUTPOSTDELETEOPTIONSMKCOLCOPYMOVEPROPFINDPROPPATCHLOCKUNLOCKPATCHTRACE
  • 返回值:
    无;无效的输入抛出错误
  • 用法:
kong.service.request.set_method("DELETE")

kong.service.request.set_query(args)

设置请求参数,与 kong.service.request.set_raw_query() 不同,args 参数必须是 table 格式,键是字符串类型,值可以是布尔值、字符串或数组,所有字符串都进行 URL 编码,生成的查询字符串根据字典顺序排序,保留同一键内的值顺序,如果需要进一步控制生成请求参数,可以使用 kong.service.request.set_raw_query() 方法

  • 段:
rewrite,access
  • 参数:
    args(table):
  • 返回值:
    无;无效的输入抛出错误
  • 用法:
kong.service.request.set_query({
  foo = "hello world",
  bar = {"baz", "bla", true},
  zzz = true,
  blo = ""
})
-- Will produce the following query string:
-- bar=baz&bar=bla&bar&blo=&foo=hello%20world&zzz

kong.service.request.set_header(header, value)

设置请求头,会覆盖已经存在的请求头,如果 header 参数是 host(大小写不敏感),会同时设置请求的 SNI

  • 段:
rewrite,access
  • 参数:
    header(string):请求头名称
    value(string,boolean,number):请求头值
  • 返回值:
    无;无效的输入抛出错误
  • 用法:
kong.service.request.set_header("X-Foo",  "value")

kong.service.request.add_header(header, value)

设置请求头,与 kong.service.request.set_header() 不同,不会覆盖已经存在的请求头

  • 段:
rewrite,access
  • 参数:
    header(string):请求头名称
    value(string,boolean,number):请求头值
  • 返回值:
    无;无效的输入抛出错误
  • 用法:
kong.service.request.add_header("Cache-Control", "no-cache")
kong.service.request.add_header("Cache-Control", "no-store")

kong.service.request.clear_header(header)

清除请求头

  • 段:
rewrite,access
  • 参数:
    header(string):请求头名称
  • 返回值:
    无;无效的输入抛出错误
  • 用法:
kong.service.request.set_header("X-Foo", "foo")
kong.service.request.add_header("X-Foo", "bar")
kong.service.request.clear_header("X-Foo")
-- from here onwards, no X-Foo headers will exist in the request

kong.service.request.set_headers(headers)

设置请求头,与 kong.service.request.set_header() 不同,headers 参数必须是 table 格式的

  • 段:
rewrite,access
  • 参数:
    headers(table):table 格式的请求头集合
  • 返回值:
    无;无效的输入抛出错误
  • 用法:
kong.service.request.set_header("X-Foo", "foo1")
kong.service.request.add_header("X-Foo", "foo2")
kong.service.request.set_header("X-Bar", "bar1")
kong.service.request.set_headers({
  ["X-Foo"] = "foo3",
  ["Cache-Control"] = { "no-store", "no-cache" },
  ["Bla"] = "boo"
})

-- Will add the following headers to the request, in this order:
-- X-Bar: bar1
-- Bla: boo
-- Cache-Control: no-store
-- Cache-Control: no-cache
-- X-Foo: foo3

kong.service.request.set_raw_body(body)

设置请求体,body 参数必须是一个字符串,不会以任何方式处理处理,这个方法还会添加 Content-Length 头,如果想设置空请求体,直接设置空字符串,更高阶的设置参考 kong.service.request.set_body()

  • 段:
rewrite,access
  • 参数:
    body(string):原始 body 请求体
  • 返回值:
    无;无效的输入抛出错误
  • 用法:
kong.service.request.set_raw_body("Hello, world!")

kong.service.request.set_body(args[, mimetype])

设置请求体,与 kong.service.request.set_body() 不同,args 必须是 table 格式,并且以 MIME type 格式编码

  1. 如果 MIME type 是 application/x-www-form-urlencoded
    以 form-encoded 方式对参数进行编码
  2. 如果 MIME type 是 multipart/form-data
    以 multipart form data 方式对参数进行编码
  3. 如果 MIME type 是 application/json
    以 JSON 格式对参数进行编码
  • 段:
rewrite,access
  • 参数:
    args(table):请求体参数,会转化成相应的格式
    mimetype(string,optional)
  • 返回值:
  1. 成功返回 true,失败返回 nil
  2. 错误返回失败信息,成果返回 nil
  • 用法:
kong.service.set_header("application/json")
local ok, err = kong.service.request.set_body({
  name = "John Doe",
  age = 42,
  numbers = {1, 2, 3}
})

-- Produces the following JSON body:
-- { "name": "John Doe", "age": 42, "numbers":[1, 2, 3] }

local ok, err = kong.service.request.set_body({
  foo = "hello world",
  bar = {"baz", "bla", true},
  zzz = true,
  blo = ""
}, "application/x-www-form-urlencoded")

-- Produces the following body:
-- bar=baz&bar=bla&bar&blo=&foo=hello%20world&zzz

kong.service.response

操作服务的响应

kong.service.response.get_status()

从服务返回的响应的 Http 状态码

  • 段:
header_filter, body_filter, log
  • 返回值:
    从服务返回的响应的 Http 状态码,整数格式;如果请求未被代理,返回 nil
  • 用法:
kong.log.inspect(kong.service.response.get_status())  -- 418

kong.service.response.get_headers([max_headers])

包含响应头的 Lua table,与 kong.response.get_headers() 不同,该方法仅会返回服务返回的响应中的请求头(忽略 Kong 本身添加的),如果请求未被代理到任何服务(比如被鉴权插件拒绝了并且产生了401响应),headers 值是 nil,因为服务没有任何响应,默认情况下,该方法最多返回100个响应头,可以指定 max_headers 调整这个值,参数范围是1至1000

  • 段:
header_filter, body_filter, log
  • 参数:
    max_header(number, optional):
  • 返回值:
  1. 响应头,table 格式
  2. 如果响应头数目超过 max_headers,返回 truncated,字符串格式
  • 用法:
-- Given a response with the following headers:
-- X-Custom-Header: bla
-- X-Another: foo bar
-- X-Another: baz
local headers = kong.service.response.get_headers()
if headers then
  kong.log.inspect(headers.x_custom_header) -- "bla"
  kong.log.inspect(headers.x_another[1])    -- "foo bar"
  kong.log.inspect(headers["X-Another"][2]) -- "baz"
end

kong.service.response.get_header(name)

返回指定响应头的值,与 kong.response.get_header() 不同,这个方法只会返回服务的响应中的请求头(忽略 Kong 本身添加的)

  • 段:
header_filter, body_filter, log
  • 参数:
    name(string):响应头的名称
  • 返回值:
    指定响应头的值,字符串格式;如果没有请求头,返回 nil
  • 用法:
-- Given a response with the following headers:
-- X-Custom-Header: bla
-- X-Another: foo bar
-- X-Another: baz

kong.log.inspect(kong.service.response.get_header("x-custom-header")) -- "bla"
kong.log.inspect(kong.service.response.get_header("X-Another"))       -- "foo bar"

kong.table

Lua table 工具类

kong.table.new([narr[, nrec]])

返回一个 table,其中包含了预先分配的数组和散列

  • 参数:
    narr(number, optional):指定在数组组件中预分布的插槽数
    nrec(number, optional):指定在散列组件中预分布的插槽数
  • 返回值:
    新创建的 table,table 格式
  • 用法:
local  tab  =  kong.table.new(4,  4)

kong.table.clear(tab)

清理 table

  • 参数:
    tab(table):需要被清理的 table
  • 返回值:
  • 用法:
local tab = {
  "hello",
  foo = "bar"
}

kong.table.clear(tab)

kong.log(tab[1]) -- nil
kong.log(tab.foo) -- nil
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容