Kong 自定义插件编写详解

最近在研究 Kong,如果你跟我一样之前对 Kong 不了解可以看他们的官网,我就不在这多说废话了。

调研了几天,Kong 的功能蛮多的,对我们也有很大的帮助,引入也很有意义,能减少我们很多操作。Kong 也比较成熟,只是网上的资料都比较零散,很多也已经随着改版而变得过时。

官网的 quickstart 也算是详细了,跟着走一遍基本就能知道个大概,有哪些功能。

我想要尝试通过自定义编写插件来更好得对数据做一些处理,就各种找资料。终于经过一段时间的冲浪后,我开始掌握了一些门道。

首先,Apache 的 skywalking-kong 帮我理清了绝大部分道路,只是不知道是因为 Kong 版本的更迭还是因为我本地环境的原因,跟 README 上描述的步骤还是有一点点的差别:

  • luarocks install kong-skywalking --localluarocks 安装 kong-plugin-skywalking,你也可以用 --tree 指定目录位置
  • 然后是 kong.conf,一般在 /etc/kong下,如果没有就 cp kong.conf.default kong.conf 然后对应配置加上,lua_package_path 注意一下写上你实际的位置,可能与 README 上的会有偏差,我的就是
  • 关键的还有一步没有写上,/usr/local/share/lua/5.1/kong/constants.lua 里记录了所有插件的名字,如果不加上的话你新加的插件也不会显示出来,需要特别注意。最后最好 kong restart

这一个走通后,就会对自定义的插件有个概念了。下面我们来自己手写一个试试,很简单的一个 Demo,主要是对 Response 的修改(只要走通了一个 其他的也就差不多了 看看官方 API)。

其实别看这里我只是轻描淡写,实际却是踩了很多坑,网上太多都是不负责任的文章,也不清楚是纯粹的 copy 还是因为版本更迭导致的失效。

我先说下网上找资料然后最终发现的几个问题:

  • local BasePlugin = require "kong.plugins.base_plugin" 这个 BasePlugin 在 2.7.x 已经废弃了,害得我还在那抓头,ChatGPT 资料库不够新,问了半天跟个傻子一样
  • kong.service.responsekong.response ,网上找到的资料都是用 kong.service.response 来改变响应体的内容,也害得我只抓头,纳闷了怎么也不行,直到我在官网 kong.response 找到了这么一句 Unlike kong.service.response, this module allows mutating the response before sending it back to the client. 我丢

然后其他的就是 Lua 脚本的编写了。

  1. 先在之前 skywalking 同级新建一个 response-handler 目录(当然也可以在 Kong 自己的插件目录中添加自定义的插件)
  2. 再进入 response-handler 目录,新建两个 Lua 脚本,插件主要也就是这两个文件 handler.luaschema.lua。至于你说这两个是什么作用,我只能说业务逻辑在 handler 中,所用到的一些可变参数在 schema 中,具体的可以自行去冲浪哈,在这我就不赘述了。下面是我写的 Demo 脚本内容:

官网资料:Plugin Configuration

handler.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
local cjson = require("cjson")

local MyPluginHandler = {
VERSION = "0.1.0", -- 版本
PRIORITY = 10 -- 脚本执行优先值
}

function MyPluginHandler:header_filter(config)
-- 修改响应头
kong.response.set_header("Handle-Response-Header", "Response-Handler")
end

function MyPluginHandler:access(conf)
end

function MyPluginHandler:body_filter(config)
-- 修改响应体
local response_body = kong.response.get_raw_body()
if response_body then
local response_json = cjson.decode(response_body)
response_json.data.num = config.num -- 我这里修改了 response.data.num 的值 (config.num 对应 schema.lua 中的 config.num)
local modified_body = cjson.encode(response_json)
kong.response.set_raw_body(modified_body)
end
end

return MyPluginHandler

schema.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
local typedefs = require "kong.db.schema.typedefs"

local PLUGIN_NAME = "myplugin"

local schema = {
name = PLUGIN_NAME,
fields = {
{ consumer = typedefs.no_consumer }, -- 该插件不能设置为 consumer
{ protocols = typedefs.protocols_http },
{ config = {
type = "record",
fields = { -- 可配置参数
{ num = {
type = "integer",
default = 10,
required = false,
gt = 0, }},
},
entity_checks = {
-- 可以写一些校验 at_least_one_of distinct
},
},
},
},
}

return schema
  1. 脚本写好后在 kong.conf 中的 plugins = bundled, skywalking, response-handler 加上
  2. /usr/local/share/lua/5.1/kong/constants.lua 中的 local plugins = {....} 加上新写的 response-handler
  3. kong restart

到这里,自定义的插件算是可以了。要还不行,那就可能是版本更迭了哈哈

文章作者: DoubleFJ
文章链接: http://putop.top/2023/06/10/kong-custom-plugin/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 DoubleFJ の Blog