apisix 自定义插件

apisix java插件,需要 java 11 的环境,而且 window 没有 netty 的 epoll 模式, 无法在本地进行插件的 deug 调试,这里直接采用 lua 开发。

1 插件存放位置

apisix 会默认加载 /user/local/apisix/plugins 下的插件,插件可以直接放在这里面。
如果是第三方的插件目录,例如目录为/xx,那么 apisix 启动时实际是扫描 /xx/apisix/plugins 目录, APISIX 要求插件父目录必须包含:apisix/plugins 子目录。
并且第三方目录需要在配置文件中指定:

apisix:
    # ...
    extra_lua_path: "/xx/?.lua"

2 怎么写自定义插件

2.1 代码示例

开发可以参考官方源码中的 example-plugin.lua 这个插件,这是一个示例代码,默认也启用了,直接复制这个进行修改即可。
比如我们创建一个 example-plugin2.lua,代码如下:
– 局部变量

local ngx = ngx
local core = require("apisix.core")
local plugin = require("apisix.plugin")
local upstream = require("apisix.upstream")

local plugin_name = "example-plugin2"

-- 插件基础信息
local _M = {
    version = 0.1,
    -- 优先级,apisix 要求每个插件的优先级都不同,这里需要注意
    priority = 1,
    -- type 如果是 auth, 则表明是认证插件,就需要配合consumer一起使用了
    -- type = 'auth',
    name = plugin_name,
    schema = schema,
    -- metadata_schema = metadata_schema,
}

-- 插件配置参数
local schema = {
    type = "object",
    properties = {
        i = {type = "number", minimum = 0},
        s = {type = "string"},
        t = {type = "array", minItems = 1},
        ip = {type = "string"},
        port = {type = "integer"},
    },
    required = {"i"},
}

-- consumer 配置,可以参考 jwt-auth.lua
--local consumer_schema = {
--    type = "object",
--    properties = {
--        ak = { type = "string" },
--        sk = { type = "string" },
--    },
--    required = { "ak", "sk" },
--}

-- 元数据配置, 可以通过/apisix/admin/plugin_metadata/{pluginName}进行元数据的配置
--local metadata_schema = {
--    type = "object",
--    properties = {
--        ikey = {type = "number", minimum = 0},
--        skey = {type = "string"},
--    },
--    required = {"ikey", "skey"},
--}

-- 校验配置合法性
function _M.check_schema(conf, schema_type)
    if schema_type == core.schema.TYPE_METADATA then
        return core.schema.check(metadata_schema, conf)
    end
    return core.schema.check(schema, conf)
end


function _M.init()
    -- call this function when plugin is loaded
    local attr = plugin.plugin_attr(plugin_name)
    if attr then
        core.log.info(plugin_name, " get plugin attr val: ", attr.val)
    end
end

-- 销毁方法,一般用于有元数据的情况,在这里面把资源是放掉
function _M.destroy()
    -- call this function when plugin is unloaded
end


function _M.rewrite(conf, ctx)
    core.log.warn("plugin rewrite phase, conf: ", core.json.encode(conf))
    core.log.warn("conf_type: ", ctx.conf_type)
    core.log.warn("conf_id: ", ctx.conf_id)
    core.log.warn("conf_version: ", ctx.conf_version)
end

--[[
阶段方法:这里写自己的逻辑
  conf 参数是插件的相关配置信息
  ctx 参数缓存了请求相关的数据信息
]]
function _M.access(conf, ctx)
    core.log.warn("plugin access phase, conf: ", core.json.encode(conf))
    -- return 200, {message = "hit example plugin"}

    if not conf.ip then
        return
    end

    local up_conf = {
        type = "roundrobin",
        nodes = {
            {host = conf.ip, port = conf.port, weight = 1}
        }
    }

    local ok, err = upstream.check_schema(up_conf)
    if not ok then
        return 500, err
    end

    local matched_route = ctx.matched_route
    upstream.set(ctx, up_conf.type .. "#route_" .. matched_route.value.id,
                 ctx.conf_version, up_conf)
    return
end


function _M.body_filter(conf, ctx)
    core.log.warn("plugin body_filter phase, eof: ", ngx.arg[2],
                  ", conf: ", core.json.encode(conf))
end


function _M.delayed_body_filter(conf, ctx)
    core.log.warn("plugin delayed_body_filter phase, eof: ", ngx.arg[2],
                  ", conf: ", core.json.encode(conf))
end


local function hello()
    local args = ngx.req.get_uri_args()
    if args["json"] then
        return 200, {msg = "world"}
    else
        return 200, "world\n"
    end
end

-- 这里和官网的略有不同,因为我想暴露端口访问 hello方法,所以这里改成了api
function _M.api()
    return {
        {
            methods = {"GET"},
            uri = "/apisix/plugin/example-plugin2/hello",
            handler = hello,
        }
    }
end


return _M

这个插件配置还是比较全的,下面我将逐个讲解每部分的作用。

2.1.1 plugin_name

plugin_name 是插件名

2.1.1 _M

这部分是插件的基本信息,包含了插件版本, 优先级,类型等等.

local _M = {
    version = 0.1,
    priority = 1,
    -- type = 'auth',
    name = plugin_name,
    schema = schema,
    metadata_schema = metadata_schema,
}

需要注意的是,如果type类型为 auth,则表示这是个认证插件,需要和 consumer_schema 连用,以指定consumer 的参数。
例如:
我希望创建一个认证插件, consumer 访问路由的时候,需要带上ak 和sk 作为鉴权,就可以在插件中加入如下配置:

local _M = {
    ...
    type = 'auth',
    ...
}

local consumer_schema = {
    type = "object",
    properties = {
        ak = { type = "string" },
        sk = { type = "string" },
    },
    required = { "ak", "sk" },
}

2.1.2 schema

schema 是创建插件的时候指定参数。

local schema = {
    type = "object",
    properties = {
        i = {type = "number", minimum = 0},
        s = {type = "string"},
        t = {type = "array", minItems = 1},
        ip = {type = "string"},
        port = {type = "integer"},
    },
    required = {"i"},
}

这段代码中的意思是,在配置这个插件的时候, 可以给定多种参数,但是 i 是必须要的,如果不指定 i ,创建时会报错。
示例:

curl -X PUT 127.0.0.1:9180/apisix/admin/routes/example_plugin2_01 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -d '
{
    "plugins": {
        "example-plugin2": {
            "name": "example2",
            "i": 1
			
        }
    },
    "upstream": {
        "type": "roundrobin",
        "nodes": {
            "xx.xx.xx.xx:8200": 1
        }
    },
    "uri": "/weave/*"
}'

2.1.3 consumer_schema

上文已经讲过了,用于指定创建 consumer 时的参数。

2.1.4 metadata_schema

元数据配置, 可以通过**/apisix/admin/plugin_metadata/{pluginName}** 接口进行元数据的配置,数据会存放到 apisix 的 etcd 数据库。

2.1.5 生命周期方法

通常来说,校验逻辑,可以写在 rewrite 阶段或者 access 阶段。
在这里插入图片描述

2.1.6 _M.api

local function hello()
    local args = ngx.req.get_uri_args()
    if args["json"] then
        return 200, {msg = "world"}
    else
        return 200, "world\n"
    end
end

function _M.api()
    return {
        {
            methods = {"GET"},
            uri = "/apisix/plugin/example-plugin2/hello",
            handler = hello,
        }
    }
end

这里和官网的略有不同,官网中的代码是 _M.control_api()。
_M.api 可以参照官网的 public api 文档,主要作用是对外暴露接口,以供访问,我这里的返回简单写了个 hello 方法,主要用于测试。
_M.control_api() 主要作用是内部访问。

3 部署

我这里是采用 docker-compose 的方式部署。

修改config.yml

将 config-default.yml 中的 plugin 部分拷贝过来, 并加上自己的插件。
配置文件在 /user/local/apisix/conf 目录下

plugins:                           # plugin list (sorted by priority)
  - example-plugin2	               # priority: 1
  xxx(把config-default.yml 中的 plugin 部分拷贝过来)

修改docker-complse.yml 文件将自己的插件挂载到容器中。
如果你是采用docker部署的,也可以将文件直接拷贝到 /user/local/apisix/apisix/plugins 目录下。

services:
  apisix:
    image: apache/apisix:${APISIX_IMAGE_TAG:-3.7.0-debian}
    restart: always
    volumes:
      - ./apisix_conf/config.yaml:/usr/local/apisix/conf/config.yaml:ro
      - ./apisix_conf/config-default.yaml:/usr/local/apisix/conf/config-default.yaml:ro
      - ./apisix_conf/example-plugin2.lua:/usr/local/apisix/apisix/plugins/example-plugin2.lua:ro

部署apisix

启动命令:docker-compose -p docker-apisix up -d
停止命令:docker-compose -p docker-apisix down
查看日志命令:docker-compose -p docker-apisix logs -f

4 测试

创建路由:

curl -X PUT 127.0.0.1:9180/apisix/admin/routes/example_plugin2_01 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -d '
{
    "plugins": {
        "example-plugin2": {
            "name": "example2",
            "i": 1
			
        }
    },
    "upstream": {
        "type": "roundrobin",
        "nodes": {
            "10.151.xx.xx:8200": 1
        }
    },
    "uri": "/test/*"
}'

开启路由的 public api:

curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/r2' \
    -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' \
    -H 'Content-Type: application/json' \
    -d '{
    "uri": "/get_hello",
    "plugins": {
        "public-api": {
            "uri": "/apisix/plugin/example-plugin2/hello"
        }
    }
}'

访问 pulibc api

curl  http://127.0.0.1:9080/get_hello -X GET 

输出如下:

在这里插入图片描述

5 补充

修改日志级别:

config-default.yml 中可以修改
在这里插入图片描述

插件的热加载:

如果只修改了插件内容,可以使用下面方法,无需重启spisix。

curl  http://127.0.0.1:9180/apisix/admin/plugins/reload -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT 
  • 29
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
API Gateway的CORS插件是一个用于处理跨域资源共享(CORS)的插件。该插件可以在请求进入API网关时,自动添加CORS响应头,以允许跨域资源访问。 使用该插件,您可以配置以下CORS相关的选项: - `allow_origins`: 允许的请求来源,可以是一个字符串,也可以是一个字符串数组。 - `allow_methods`: 允许的HTTP方法,可以是一个字符串,也可以是一个字符串数组。 - `allow_headers`: 允许的HTTP头,可以是一个字符串,也可以是一个字符串数组。 - `expose_headers`: 允许客户端访问的HTTP头,可以是一个字符串,也可以是一个字符串数组。 - `max_age`: 预检请求的有效期,单位为秒。 - `allow_credentials`: 是否允许发送cookie等凭证信息。 下面是一个使用API Gateway的CORS插件的示例: ```yaml plugins: - name: cors config: allow_origins: "*" allow_methods: "GET,POST,PUT" allow_headers: "Content-Type" expose_headers: "X-Custom-Header" max_age: 3600 allow_credentials: true ``` 在上面的示例中,我们配置了允许任何来源的GET、POST和PUT请求,允许的HTTP头为Content-Type,允许客户端访问X-Custom-Header头,预检请求的有效期为3600秒,并且允许发送cookie等凭证信息。 需要注意的是,在使用CORS插件时,您需要将其添加到特定的路由或服务上。例如,您可以将其添加到一个特定的API上,或者将其添加到一个服务上,以处理该服务下的所有API

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值