本地变量
本地声明的常量, 直接使用
local ALGORITHM = "SHA256"
-- 生成签名
local function generate_signature(rsa_private_key, signing_string)
local privateObject, err = resty_rsa:new({ private_key = rsa_private_key, algorithm = ALGORITHM })
if not privateObject then
return nil, err
end
local signature, err = privateObject:sign(signing_string)
if not signature then
return nil, err
end
return signature
end
配置
启用插件时, 输入的配置
以 echo.lua 插件举例
启用echo插件需要的配置
-- 启用插件时, 需要填写的配置, 最后一行的意思是, 必须填一个
local schema = {
type = "object",
properties = {
before_body = {
description = "body before the filter phase.",
type = "string"
},
body = {
description = "body to replace upstream response.",
type = "string"
},
after_body = {
description = "body after the modification of filter phase.",
type = "string"
},
headers = {
description = "new headers for response",
type = "object",
minProperties = 1,
},
},
anyOf = {
{required = {"before_body"}},
{required = {"body"}},
{required = {"after_body"}}
},
minProperties = 1,
}
启用echo插件
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"plugins": {
"echo": {
"before_body": "before the body modification "
}
},
"upstream": {
"nodes": {
"127.0.0.1:9081": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}'
配置的获取
conf.before_body
function _M.body_filter(conf, ctx)
if conf.body then
ngx.arg[1] = conf.body
ngx.arg[2] = true
end
if conf.before_body and not ctx.plugin_echo_body_set then
ngx.arg[1] = conf.before_body .. ngx.arg[1]
ctx.plugin_echo_body_set = true
end
if ngx.arg[2] and conf.after_body then
ngx.arg[1] = ngx.arg[1] .. conf.after_body
end
end
属性
属性需要配置在配置文件中, 需重启
以log-rotate.lua插件为例
配置文件路径以及配置内容
# 配置文件路径
vim /usr/local/apisix/conf/config.yaml
# 插件属性配置
plugin_attr:
log-rotate:
interval: 1800 # rotate interval (unit: second)
max_kept: 20 # max number of log files will be kept
enable_compression: true # enable log file compression(gzip) or not, default false
属性获取
local plugin = require("apisix.plugin")
local plugin_name = "echo"
local function rotate()
local interval = INTERVAL
local max_kept = MAX_KEPT
local attr = plugin.plugin_attr(plugin_name)
if attr then
interval = attr.interval or interval
max_kept = attr.max_kept or max_kept
enable_compression = attr.enable_compression or enable_compression
end
end
元数据
参考example-plugin.lua
配置
-- 需要一个ikey, 一个skey
local metadata_schema = {
type = "object",
properties = {
ikey = {type = "number", minimum = 0},
skey = {type = "string"},
},
required = {"ikey", "skey"},
}
修改
curl http://127.0.0.1:9080/apisix/admin/plugin_metadata/example-plugin -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -i -X PUT -d '
{
"skey": "val",
"ikey": 1
}'
HTTP/1.1 201 Created
Date: Thu, 26 Dec 2019 04:19:34 GMT
Content-Type: text/plain
存储
元数据的存储存在etcd中
# 路径
etcdctl get /apisix/plugin_metadata/example-plugin
# 保存在etcd中的数据格式
/apisix/plugin_metadata/example-plugin
{"skey":"val","ikey":1}
获取
local plugin = require("apisix.plugin")
local plugin_name = "example-plugin"
# 获取并打印
local metadata = plugin.plugin_metadata(plugin_name)
core.log.warn("metadata: ", core.json.encode(metadata))
# 代码中的数据格式
{"value":{"skey":"val","ikey":1,"id":"plugin-test"}
注意事项以及其他说明
- 元数据不在代码中声明, 也是可以直接调用接口修改的; 代码中声明, 可以控制必须入参
- 元数据可以全局使用, 但是如果某个值不更新的话, 会被删除掉
如下, 我修改了一个test的值, 然后再修改回去的时候, test已经没有了, 不会一直存在
curl http://127.0.0.1:9080/apisix/admin/plugin_metadata/example-plugin -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -i -X PUT -d '
{
"skey": "val2",
"ikey": 2,
"test": "test"
}'
curl http://127.0.0.1:9080/apisix/admin/plugin_metadata/example-plugin -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -i -X PUT -d '
{
"skey": "val3",
"ikey": 5
}'
参考文档
https://apisix.apache.org/zh/docs/apisix/admin-api/#plugin-metadata
etcd
如果想让某个插件, 或者所有插件使用一个全局变量值的话, 可以放在etcd中
etcd客户端的插入, 查询
# 插入
etcdctl put /apisix/plugin-test/test 5
# 获取
etcdctl get /apisix/plugin-test/test 5
# 删除
etcdctl del /apisix/takin-apisix-server/cluster
apisix中etcd插入, 查询
注意: apisix操作etcd, 默认前缀为 /apisix
local core = require("apisix.core")
# 插入
local res, err = core.etcd.set(key, value)
# 获取
local res, err = core.etcd.get(key)
core.log.warn("res: ", core.json.encode(res.body))
# 获取的数据结构, 数据在res.body.node.value下
{"header":{"revision":"8096","cluster_id":"14841639068965178418","raft_term":"60","member_id":"10276657743932975437"},"action":"get","node":{"modifiedIndex":8075,"value":{"skey":"val","ikey":1},"key":"\/apisix\/plugin_metadata\/plugin-test","createdIndex":8075},"count":"1"}
插件中的使用
使用插件可以注册接口, 通过接口, 修改etcd的值, 来使用
注册接口参考文档 https://apisix.apache.org/zh/docs/apisix/plugin-develop/#注册公共接口
local core = require("apisix.core")
local plugin_name = "plugin-test"
-- 更新接口对应的方法
local function plugin_update()
-- 拿到请求体, 然后反序列化
-- 获取值, 赋值
local body = core.request.get_body()
if not body then
return 500, {msg = "没有数据"}
end
local data, err = core.json.decode(body)
if not data then
return 500, {msg = "json反序列化失败" .. err}
end
if not data.value then
return 500, {msg = "值必须填写"}
end
local etcd_key = xxx
local res, err2 = core.etcd.set(etcd_key, data.value)
if not res then
return 500, {msg = "存入etcd失败, 详细信息: " .. err2 }
end
return 200
end
-- 公共接口
function _M.api()
return {
{
methods = {"PUT"},
uri = "/apisix/plugin/" .. plugin_name,
handler = plugin_update,
}
}
end
apisix自定义变量
参考: https://github.com/apache/apisix/issues/6702
注意事项
注册的自定义变量不能作为全局变量来使用
因为自定义变量是有生命周期的, 下一个请求就会重新生成 TODO
自定义变量而且存在每个worker下的内存中的 TODO
如果提供了一个接口去修改, 可能只修改了某个worker下的自定义变量
参考文档
https://apisix.apache.org/zh/docs/apisix/plugin-develop/#注册自定义变量
其他
IPC 进程间通信