如何在APISIX中扩展功能:添加自定义插件全攻略

一、APISIX插件机制概述

APISIX作为基于Nginx和Lua开发的高性能API网关,其插件系统采用模块化设计,通过”钩子”(Hooks)机制在请求生命周期的不同阶段(如访问、认证、限流、日志等)插入自定义逻辑。官方已提供超过60个内置插件,但当业务需要特殊处理时(如自定义鉴权、数据脱敏等),开发者可通过Lua语言编写自定义插件。

插件运行流程分为初始化、配置加载、请求处理三个阶段。初始化阶段加载插件元数据,配置加载阶段解析路由/服务绑定的插件参数,请求处理阶段按顺序执行插件逻辑。这种设计保证了插件的独立性和可扩展性。

二、自定义插件开发规范

1. 插件目录结构

标准插件应放置在apisix/plugins/目录下,包含以下文件:

  1. my-plugin/
  2. ├── handler.lua # 核心逻辑
  3. ├── schema.lua # 配置校验
  4. ├── access.lua # 访问阶段处理(可选)
  5. ├── rewrite.lua # 重写阶段处理(可选)
  6. └── meta.lua # 元数据定义(APISIX 2.10+)

2. 核心组件实现

2.1 插件元数据(meta.lua)

  1. local meta = {
  2. version = "0.1",
  3. priority = 1000, -- 执行优先级(数字越小越早执行)
  4. name = "my-plugin",
  5. type = "traffic" -- 插件类型(traffic/security等)
  6. }
  7. return meta

2.2 配置校验(schema.lua)

  1. local schema = {
  2. type = "object",
  3. properties = {
  4. enable = {type = "boolean", default = true},
  5. threshold = {type = "number", minimum = 1}
  6. },
  7. required = {"threshold"}
  8. }
  9. return {
  10. type = "object",
  11. properties = schema
  12. }

2.3 核心逻辑(handler.lua)

  1. local handler = {}
  2. -- 初始化函数(可选)
  3. function handler.init()
  4. -- 加载外部依赖等操作
  5. end
  6. -- 访问阶段处理
  7. function handler.access(conf, ctx)
  8. local threshold = conf.threshold
  9. if tonumber(ctx.var.remote_addr) > threshold then
  10. return 403, {message = "IP exceeded limit"}
  11. end
  12. end
  13. -- 日志阶段处理(可选)
  14. function handler.log(conf, ctx)
  15. -- 记录自定义日志
  16. end
  17. return handler

三、插件注册与配置

1. 启用插件

  1. 修改conf/config.yaml

    1. plugins:
    2. - my-plugin # 添加自定义插件名
  2. 创建插件目录(若不存在):

    1. mkdir -p /usr/local/apisix/plugins/my-plugin
  3. 重启APISIX使配置生效:

    1. apisix restart

2. 路由绑定配置

通过Admin API动态绑定插件:

  1. curl http://127.0.0.1:9180/apisix/admin/routes/1 \
  2. -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' \
  3. -X PUT -d '{
  4. "uri": "/test",
  5. "plugins": {
  6. "my-plugin": {
  7. "threshold": 1000,
  8. "enable": true
  9. }
  10. },
  11. "upstream": {
  12. "type": "roundrobin",
  13. "nodes": {
  14. "127.0.0.1:8080": 1
  15. }
  16. }
  17. }'

四、高级功能实现

1. 依赖管理

插件可引入外部Lua模块,建议使用:

  1. local cjson = require "cjson.safe"
  2. local lrucache = require "apisix.core.lrucache"

2. 状态保持

通过APISIX提供的ctx对象传递数据:

  1. function handler.access(conf, ctx)
  2. ctx.my_plugin_data = {timestamp = ngx.now()}
  3. end
  4. function handler.header_filter(conf, ctx)
  5. ngx.header["X-Plugin-Time"] = ctx.my_plugin_data.timestamp
  6. end

3. 异步处理

使用APISIX的ngx.timer.at实现异步任务:

  1. local timer = require "apisix.core.timer"
  2. function handler.log(conf, ctx)
  3. local delay = 5 -- 5秒后执行
  4. timer.running(delay, function()
  5. -- 异步日志处理
  6. end)
  7. end

五、调试与优化

1. 日志调试

在插件中添加日志输出:

  1. local core = require "apisix.core"
  2. function handler.access(conf, ctx)
  3. core.log.warn("Plugin triggered with conf: ", core.json.encode(conf))
  4. end

2. 性能优化

  • 使用LRU缓存存储频繁访问的数据
  • 避免在请求处理阶段进行阻塞操作
  • 对计算密集型任务使用协程

3. 测试方法

  1. 使用wrk进行压力测试:

    1. wrk -t12 -c400 -d30s http://127.0.0.1:9080/test
  2. 通过Admin API检查插件执行状态:

    1. curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/my-plugin

六、实际案例解析

案例:IP白名单插件

  1. -- handler.lua
  2. local ip = require "resty.iputils"
  3. local _M = {}
  4. function _M.check_schema(conf)
  5. if not ip.check_ip(conf.allowed_ips) then
  6. return false, "invalid IP format"
  7. end
  8. return true
  9. end
  10. function _M.access(conf, ctx)
  11. local client_ip = ctx.var.remote_addr
  12. if not ip.ip_in_cidrs(client_ip, {conf.allowed_ips}) then
  13. return 403, {message = "IP not allowed"}
  14. end
  15. end
  16. return _M

配置示例:

  1. {
  2. "uri": "/secure",
  3. "plugins": {
  4. "ip-whitelist": {
  5. "allowed_ips": "192.168.1.0/24"
  6. }
  7. }
  8. }

七、最佳实践建议

  1. 命名规范:插件名使用小写字母和连字符(如rate-limiting
  2. 版本控制:在元数据中明确版本号,便于升级管理
  3. 配置默认值:在schema中设置合理的默认参数
  4. 错误处理:统一错误响应格式,包含错误码和描述
  5. 文档完善:编写详细的README说明插件功能、配置项和示例

通过遵循上述规范,开发者可以高效地实现从简单鉴权到复杂流量控制的各类自定义插件。APISIX的插件机制设计既保证了灵活性,又通过校验机制确保了系统稳定性,是构建企业级API网关的理想选择。