Kong[nginx]-12 插件开发实践(redis)
2019-08-12 本文已影响7人
国服最坑开发
0x00 前言
上一篇我们聊到自定义插件的用途, 这里我们实践一下: 把API网关做为接口服务提供者来使用.
(这种用法, 虽然有点不务正业, 不过至少给后端开发者多提供了一些脑洞. 至于实际的使用场景,请小伙伴们自由发挥, 可以在评论区留下您的想法 :-)
0x01 准备
按着以前积累的经验, 我们这里, 先快速创建一个自定义插件,名称为sum-api
下面是两个文件的代码:
- handler.lua
local BasePlugin = require "kong.plugins.base_plugin"
local SumHandler = BasePlugin:extend()
SumHandler.VERSION = "1.0.0"
SumHandler.PRIORITY = 10
function SumHandler:access(config)
local rst = {}
return kong.response.exit(200, rst,
{
["Content-Type"] = "application/json",
})
end
return SumHandler
- schema.lua
local typedefs = require "kong.db.schema.typedefs"
local colon_string_array = {
type = "array",
default = {},
elements = { type = "string", match = "^[^:]+:.*$" },
}
return {
name = "robot",
fields = {
{ protocols = typedefs.protocols_http },
{ config = {
type = "record",
fields = {
{ sitename = colon_string_array }
},
},
},
},
}
接下来, 修改/etc/kong/kong.conf
, 加载插件名称 sum-api
, 并重启服务kong restart
.
然后按照下面的图片顺序, 添加一个的router
取名为 /sum-api
,并启用我们插件.
OK, 到此准备工作完成.
接下来的流程就是:
- 修改代码
- 重启服务
kong restart
- 校验接口
curl -i 'http://aaa.com/sum-api?a=1&b=2'
0x02 开发简单接口服务
这里先开发一个简单的例子: 在URL里给出两个参数
a
和b
,在Lua插件里直接返回计算结果.
返回格式为,API常用格式:JSON
- 话不多说, 直接上代码:
-- handler.lua
local BasePlugin = require "kong.plugins.base_plugin"
local SumHandler = BasePlugin:extend()
SumHandler.VERSION = "1.0.0"
SumHandler.PRIORITY = 10
function SumHandler:access(config)
-- 从URL里提取参数, 如果没有的话, 给默认值 '0'
local a = kong.request.get_query_arg('a') or '0'
local b = kong.request.get_query_arg('b') or '0'
-- String转型为数值型
local sum = tonumber(a) + tonumber(b)
-- 创建一个Lua Table
local rst = {}
rst["errCode"] = 0
-- Lua的字符串拼接
rst["msg"] = a .. '+' .. b .. '=' .. sum
-- 这里直接向客户端返回结果
return kong.response.exit(200, rst,
{
["Content-Type"] = "application/json",
})
end
return SumHandler
-
跑接口看一下结果:
sum-api
恩, 朕很满意 : )
0x03 使用redis功能
-
redis
简易安装教程
yum install epel-release
yum install redis
service redis start
redis验证
- 功能开发
我们为上面的接口增加一个访问次数的信息
同时, openresty中已经包含了redis的操作库, 所以这个功能实现起来不难
-- handler.lua
local BasePlugin = require "kong.plugins.base_plugin"
-- 调用模块
local redisUtil = require "kong.plugins.sum-api.redisUtil"
local redis = redisUtil.new()
local SumHandler = BasePlugin:extend()
SumHandler.VERSION = "1.0.0"
SumHandler.PRIORITY = 10
function SumHandler:access(config)
local a = kong.request.get_query_arg('a') or '0'
local b = kong.request.get_query_arg('b') or '0'
local sum = tonumber(a) + tonumber(b)
-- 调用redis
local res, err = redis:exec(
function(red)
red:init_pipeline()
red:incr('access_count')
return red:commit_pipeline()
end
)
local rst = {}
rst["errCode"] = 0
rst["msg"] = a .. '+' .. b .. '=' .. sum
rst["count"] = res
return kong.response.exit(200, rst,
{
["Content-Type"] = "application/json",
})
end
return SumHandler
- redisUtil.lua
local redis = require "resty/redis"
local log = ngx.log
local ERR = ngx.ERR
local setmetatable = setmetatable
local _M = {
}
local mt = { __index = _M }
local function errlog(...)
log(ERR, "Redis: ", ...)
end
function _M.exec(self, func)
local red = redis:new()
red:set_timeout(self.timeout)
local ok, err = red:connect(self.host, self.port)
if not ok then
errlog("Cannot connect, host: " .. self.host .. ", port: " .. self.port)
return nil, err
end
if self.password ~= '' then
local count
count, err = red:get_reused_times()
if 0 == count then
ok, err = red:auth(self.password)
if not ok then
ngx.say("failed to auth: ", err)
return
end
elseif err then
ngx.say("failed to get reused times: ", err)
return
end
end
red:select(self.database)
local res, err = func(red)
if res then
local ok, err = red:set_keepalive(self.max_idle_time, self.pool_size)
if not ok then
red:close()
end
end
return res, err
end
function _M.new(opts)
local config = opts or {}
local self = {
host = config.host or "127.0.0.1",
password = config.password or '',
port = config.port or 6379,
timeout = config.timeout or 5000,
database = config.database or 0,
max_idle_time = config.max_idle_time or 60000,
pool_size = config.pool_size or 100
}
return setmetatable(self, mt)
end
return _M
程序代码结构图:
代码结构
-
多次访问接口,验证结果
访问次数
完美, 收工!