本地變量
本地聲明的常量, 直接使用
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 進程間通信