apisix-插件开发-值的获取

本地变量

本地声明的常量, 直接使用

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 进程间通信

posted @ 2022-04-17 22:52  loseself  阅读(1269)  评论(0编辑  收藏  举报