0x00 前言
上一篇我們聊到自定義插件的用途, 這里我們實(shí)踐一下: 把API網(wǎng)關(guān)做為接口服務(wù)提供者來使用.
(這種用法, 雖然有點(diǎn)不務(wù)正業(yè), 不過至少給后端開發(fā)者多提供了一些腦洞. 至于實(shí)際的使用場景,請小伙伴們自由發(fā)揮, 可以在評(píng)論區(qū)留下您的想法 :-)
0x01 準(zhǔn)備
按著以前積累的經(jīng)驗(yàn), 我們這里, 先快速創(chuàng)建一個(gè)自定義插件,名稱為sum-api
下面是兩個(gè)文件的代碼:
- 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
, 并重啟服務(wù)kong restart
.
然后按照下面的圖片順序, 添加一個(gè)的router
取名為 /sum-api
,并啟用我們插件.
選擇Service
添加Router
設(shè)置一個(gè)不存在的Router: /sum-api
選擇Router
為此Router添加插件
選擇Sum Api插件
插件參數(shù)設(shè)置
OK, 到此準(zhǔn)備工作完成.
接下來的流程就是:
- 修改代碼
- 重啟服務(wù)
kong restart
- 校驗(yàn)接口
curl -i 'http://aaa.com/sum-api?a=1&b=2'
0x02 開發(fā)簡單接口服務(wù)
這里先開發(fā)一個(gè)簡單的例子: 在URL里給出兩個(gè)參數(shù)
a
和b
,在Lua插件里直接返回計(jì)算結(jié)果.
返回格式為,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里提取參數(shù), 如果沒有的話, 給默認(rèn)值 '0'
local a = kong.request.get_query_arg('a') or '0'
local b = kong.request.get_query_arg('b') or '0'
-- String轉(zhuǎn)型為數(shù)值型
local sum = tonumber(a) + tonumber(b)
-- 創(chuàng)建一個(gè)Lua Table
local rst = {}
rst["errCode"] = 0
-- Lua的字符串拼接
rst["msg"] = a .. '+' .. b .. '=' .. sum
-- 這里直接向客戶端返回結(jié)果
return kong.response.exit(200, rst,
{
["Content-Type"] = "application/json",
})
end
return SumHandler
-
跑接口看一下結(jié)果:
sum-api
恩, 朕很滿意 : )
0x03 使用redis功能
-
redis
簡易安裝教程
yum install epel-release
yum install redis
service redis start
redis驗(yàn)證
- 功能開發(fā)
我們?yōu)樯厦娴慕涌谠黾右粋€(gè)訪問次數(shù)的信息
同時(shí), openresty中已經(jīng)包含了redis的操作庫, 所以這個(gè)功能實(shí)現(xiàn)起來不難
-- handler.lua
local BasePlugin = require "kong.plugins.base_plugin"
-- 調(diào)用模塊
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)
-- 調(diào)用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
程序代碼結(jié)構(gòu)圖:
代碼結(jié)構(gòu)
-
多次訪問接口,驗(yàn)證結(jié)果
訪問次數(shù)
完美, 收工!