Apache APISIX插件开发完全指南:从入门到精通
【免费下载链接】apisix The Cloud-Native API Gateway 项目地址: https://gitcode.com/GitHub_Trending/ap/apisix
概述
Apache APISIX作为云原生API网关,其插件系统是其最强大的特性之一。通过插件机制,开发者可以轻松扩展网关功能,实现自定义的业务逻辑。本文将深入探讨APISIX插件开发的完整流程,从基础概念到高级技巧,帮助您全面掌握插件开发技能。
插件架构深度解析
核心架构组件
APISIX插件系统基于OpenResty和Lua构建,采用模块化设计:
插件生命周期管理
每个插件都遵循严格的生命周期管理:
开发环境搭建
基础环境要求
# 安装OpenResty和依赖
sudo yum install -y openresty openresty-devel
# 安装APISIX
wget https://github.com/apache/apisix/releases/download/3.8.0/apisix-3.8.0-0.el7.x86_64.rpm
sudo yum install -y apisix-3.8.0-0.el7.x86_64.rpm
# 启动APISIX
apisix start
项目结构规划
建议的插件开发目录结构:
├── custom-plugins/
│ └── apisix/
│ ├── plugins/
│ │ ├── my-custom-plugin.lua
│ │ └── another-plugin.lua
│ └── stream/
│ └── plugins/
│ └── stream-plugin.lua
└── config.yaml
插件开发实战
基础插件模板
local ngx = ngx
local core = require("apisix.core")
local plugin = require("apisix.plugin")
-- 插件配置Schema定义
local schema = {
type = "object",
properties = {
enabled = {type = "boolean", default = true},
threshold = {type = "number", minimum = 0, default = 100},
timeout = {type = "integer", minimum = 1, default = 30},
whitelist = {
type = "array",
items = {type = "string"},
default = {}
}
},
required = {"enabled"}
}
-- 元数据Schema(可选)
local metadata_schema = {
type = "object",
properties = {
version = {type = "string"},
description = {type = "string"}
}
}
local plugin_name = "my-custom-plugin"
local _M = {
version = 1.0,
priority = 500, -- 执行优先级
name = plugin_name,
schema = schema,
metadata_schema = metadata_schema,
type = "traffic", -- 插件类型:auth/traffic/log等
}
-- 配置验证
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()
core.log.info("插件初始化: ", plugin_name)
-- 初始化逻辑
end
-- 插件清理
function _M.destroy()
core.log.info("插件卸载: ", plugin_name)
-- 清理逻辑
end
-- rewrite阶段处理
function _M.rewrite(conf, ctx)
if not conf.enabled then
return
end
core.log.info("rewrite阶段执行: ", core.json.encode(conf))
-- 请求重写逻辑
end
-- access阶段处理
function _M.access(conf, ctx)
if not conf.enabled then
return
end
-- 访问控制逻辑
local client_ip = ctx.var.remote_addr
for _, ip in ipairs(conf.whitelist) do
if client_ip == ip then
core.log.info("IP白名单通过: ", client_ip)
return
end
end
-- 业务逻辑处理
if conf.threshold > 0 then
-- 限流检查等
end
core.log.info("access阶段执行完成")
end
-- 响应体过滤
function _M.body_filter(conf, ctx)
if not conf.enabled then
return
end
local chunk = ngx.arg[1]
local eof = ngx.arg[2]
if chunk and not eof then
-- 响应体处理逻辑
ngx.arg[1] = chunk .. "\n<!-- Processed by My Custom Plugin -->"
end
end
return _M
配置验证最佳实践
-- 增强型配置验证
function _M.check_schema(conf, schema_type)
local ok, err = core.schema.check(schema, conf)
if not ok then
return false, err
end
-- 自定义验证逻辑
if conf.threshold > 1000 and conf.timeout < 10 then
return false, "阈值过高时超时时间不能小于10秒"
end
-- IP地址格式验证
for _, ip in ipairs(conf.whitelist) do
if not core.ip.is_ipv4(ip) and not core.ip.is_ipv6(ip) then
return false, "无效的IP地址: " .. ip
end
end
return true
end
高级插件特性
自定义变量注册
-- 注册自定义变量
core.ctx.register_var("custom_plugin_metric", function(ctx)
local route = ctx.matched_route and ctx.matched_route.value
if route and route.plugins and route.plugins[plugin_name] then
return route.plugins[plugin_name].threshold or 0
end
return nil
end)
-- 使用自定义变量
function _M.access(conf, ctx)
local metric = ctx.var.custom_plugin_metric
core.log.info("自定义变量值: ", metric)
end
控制API注册
-- 注册控制API
local function get_plugin_stats()
local args = ngx.req.get_uri_args()
local stats = {
processed_requests = 1000,
active_connections = 42,
config = args.config or "default"
}
if args.format == "json" then
return 200, stats
else
return 200, "Processed: " .. stats.processed_requests
end
end
function _M.control_api()
return {
{
methods = {"GET"},
uris = {"/v1/plugin/my-plugin/stats"},
handler = get_plugin_stats,
}
}
end
公共API注册
-- 注册公共API
local function public_endpoint()
local headers = ngx.req.get_headers()
local response = {
status = "success",
timestamp = ngx.now(),
data = {
message = "Hello from custom plugin API",
headers = headers
}
}
return 200, response
end
function _M.api()
return {
{
methods = {"GET", "POST"},
uri = "/apisix/plugin/my-plugin/endpoint",
handler = public_endpoint,
}
}
end
性能优化技巧
内存管理最佳实践
-- 使用LRU缓存减少重复计算
local lrucache = require("apisix.core.lrucache")
local plugin_cache = lrucache.new(100) -- 100个缓存项
function _M.access(conf, ctx)
local cache_key = ctx.var.host .. ctx.var.uri
local cached_result = plugin_cache:get(cache_key)
if cached_result then
return cached_result
end
-- 耗时的计算逻辑
local result = perform_expensive_operation(conf, ctx)
plugin_cache:set(cache_key, result, 60) -- 缓存60秒
return result
end
异步处理模式
-- 使用ngx.timer进行异步处理
function _M.log(conf, ctx)
local ok, err = ngx.timer.at(0, function(premature, conf_data, ctx_data)
if premature then
return
end
-- 异步处理日志记录
process_log_async(conf_data, ctx_data)
end, conf, ctx)
if not ok then
core.log.error("failed to create timer: ", err)
end
end
测试策略
单元测试编写
-- test/my-custom-plugin.t
=== TEST 1: 基础功能测试
--- config
location /t {
content_by_lua_block {
local plugin = require("apisix.plugins.my-custom-plugin")
local conf = {enabled = true, threshold = 100}
local ok, err = plugin.check_schema(conf)
if not ok then
ngx.say("Schema验证失败: ", err)
return
end
ngx.say("Schema验证通过")
}
}
--- request
GET /t
--- response_body
Schema验证通过
--- no_error_log
[error]
=== TEST 2: 边界条件测试
--- config
location /t {
content_by_lua_block {
local plugin = require("apisix.plugins.my-custom-plugin")
local conf = {enabled = true, threshold = 10000, timeout = 5}
local ok, err = plugin.check_schema(conf)
if ok then
ngx.say("验证通过")
else
ngx.say("验证失败: ", err)
end
}
}
--- request
GET /t
--- response_body
验证失败: 阈值过高时超时时间不能小于10秒
--- no_error_log
[error]
集成测试示例
=== TEST 1: 插件集成测试
--- config
location /test-plugin {
content_by_lua_block {
ngx.say("Original response")
}
}
--- pipelined_requests eval
[
"GET /test-plugin",
"GET /test-plugin?debug=1"
]
--- response_body eval
[
"Original response\n<!-- Processed by My Custom Plugin -->",
"Original response\n<!-- Processed by My Custom Plugin -->"
]
--- error_code eval
[200, 200]
部署与配置
配置文件设置
# conf/config.yaml
apisix:
node_listen: 9080
extra_lua_path: "/path/to/custom-plugins/?.lua"
# 插件配置
plugins:
- my-custom-plugin
- limit-req
- key-auth
- prometheus
# 数据加密配置(可选)
data_encryption:
enable: true
keyring:
- edd1c9f0985e76a2
- qeddd145sfvddff4
# 自定义插件配置示例
plugin_attr:
my-custom-plugin:
default_threshold: 200
max_timeout: 60
路由配置示例
{
"uri": "/api/*",
"plugins": {
"my-custom-plugin": {
"enabled": true,
"threshold": 500,
"timeout": 30,
"whitelist": ["192.168.1.100", "10.0.0.1"]
},
"limit-req": {
"rate": 100,
"burst": 50,
"key": "remote_addr"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"backend1:8080": 1,
"backend2:8080": 1
}
}
}
故障排查与调试
日志调试技巧
function _M.access(conf, ctx)
-- 详细调试信息
core.log.debug("插件配置: ", core.json.encode(conf))
core.log.debug("请求上下文: ", core.json.encode({
method = ctx.var.request_method,
uri = ctx.var.request_uri,
headers = ngx.req.get_headers()
}, true))
-- 性能监控
local start_time = ngx.now()
-- 业务逻辑处理
local elapsed = ngx.now() - start_time
core.log.info("处理耗时: ", elapsed, "秒")
end
常见问题解决
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 插件未生效 | 配置未加载 | 检查extra_lua_path配置 |
| Schema验证失败 | 配置格式错误 | 使用core.schema.check验证 |
| 性能问题 | 重复计算 | 使用LRU缓存优化 |
| 内存泄漏 | 全局变量滥用 | 使用local变量,及时清理 |
安全最佳实践
输入验证
function _M.access(conf, ctx)
-- SQL注入防护
local user_input = ngx.var.arg_input
if user_input and not validate_input(user_input) then
return 400, {error = "Invalid input detected"}
end
-- XSS防护
local headers = ngx.req.get_headers()
for key, value in pairs(headers) do
if is_xss_payload(value) then
core.log.warn("XSS攻击尝试: ", key, ": ", value)
return 403, {error = "Security violation"}
end
end
end
local function validate_input(input)
-- 实现严格的输入验证逻辑
return not input:match("[%c%z]") -- 禁止控制字符
end
敏感数据保护
-- 在schema中定义加密字段
local schema = {
type = "object",
properties = {
api_key = {type = "string"},
secret_token = {type = "string"}
},
encrypt_fields = {"api_key", "secret_token"}
}
监控与观测
指标收集
local prometheus = require("apisix.plugins.prometheus")
function _M.access(conf, ctx)
local metric_labels = {
route = ctx.var.host .. ctx.var.uri,
plugin = plugin_name
}
-- 记录请求计数
prometheus:counter("plugin_requests_total", "Total plugin requests", metric_labels):inc(1)
-- 记录处理时间
local start_time = ngx.now()
-- 业务逻辑处理
local processing_time = ngx.now() - start_time
prometheus:histogram("plugin_processing_seconds", "Plugin processing time", metric_labels):observe(processing_time)
end
总结
通过本文的全面介绍,您应该已经掌握了Apache APISIX插件开发的核心技能。从基础插件结构到高级特性,从性能优化到安全实践,每个环节都需要仔细考虑。记住良好的插件设计应该遵循以下原则:
- 单一职责:每个插件只处理一个明确的业务功能
- 配置驱动:通过配置而非代码修改来调整行为
- 性能优先:尽量减少对请求处理时间的影响
- 安全可靠:严格验证输入,保护敏感数据
- 易于观测:提供充分的日志和监控指标
通过不断实践和优化,您将能够开发出高质量、高性能的APISIX插件,为您的API网关注入强大的自定义能力。
【免费下载链接】apisix The Cloud-Native API Gateway 项目地址: https://gitcode.com/GitHub_Trending/ap/apisix
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



