跳到主要内容
版本:3.10.x

Serverless 函数还是自定义插件

API7 网关提供两种在请求生命周期中运行自有 Lua 逻辑的方式:内置 serverless-function 插件自定义 Lua 插件。两者都会执行你编写的 Lua,并具有相同的网关运行时访问权限;区别在于代码的打包、配置、治理和复用方式。

经验法则是:小型、一次性代码片段使用 Serverless 函数;任何需要复用或较复杂的逻辑使用自定义插件

Serverless 函数

serverless-pre-functionserverless-post-function插件运行直接粘贴到路由、服务、消费者或全局规则中的内联 Lua。无需上传或注册,代码就是资源配置中的一个字段。完整配置请参阅 Serverless Functions插件参考。

每个实例在单个 phase 中运行一个 functions 列表。每个函数都是返回函数的 Lua 字符串。返回的函数接收插件配置和请求上下文,因此完整签名是 function(conf, ctx),也可以忽略它们而不接收参数:

{
"plugins": {
"serverless-pre-function": {
"phase": "access",
"functions": [
"return function(conf, ctx) local core = require('apisix.core'); core.request.set_header(ctx, 'X-Trace-ID', 'demo') end"
]
}
}
}
  • phase——运行逻辑的唯一阶段:rewriteaccessheader_filterbody_filterlogbefore_proxy,默认为 access
  • functions——Lua 源代码字符串数组,每个字符串返回一个 function(conf, ctx)。它们按顺序运行;如果某个函数返回状态码或响应体,请求会提前结束。

serverless-pre-function 较早运行(优先级 10000),serverless-post-function 较晚运行(优先级 -2000),因此它们通常用于在某个阶段的最开始或最末尾注入逻辑。

自定义插件

自定义插件是从 Dashboard 上传一次的 Lua 模块。控制面解析其 nameversionschema,将其分发到选定的网关组,随后它会像内置插件一样出现在插件选择器中。你可以通过类型化字段为每个路由或服务配置插件,而不是粘贴代码。

local core = require("apisix.core")

local schema = {
type = "object",
properties = {
header_name = { type = "string", default = "X-Trace-ID" },
header_value = { type = "string" },
},
required = { "header_value" },
}

local _M = {
version = 0.1,
priority = 1500,
name = "custom-header",
schema = schema,
}

function _M.check_schema(conf)
return core.schema.check(schema, conf)
end

function _M.access(conf, ctx)
core.request.set_header(ctx, conf.header_name, conf.header_value)
end

return _M

对比

维度Serverless 函数自定义插件
代码位置内联在各资源配置中上传到控制面的具名模块
复用复制并粘贴到每个需要它的资源注册一次,即可在任何已部署网关组中按名称引用
配置无;参数硬编码在 Lua 字符串中由带默认值的 JSON schema 验证类型化字段
名称和版本解析并强制使用(nameversion
优先级固定为 10000(较早)或 -2000(较晚)由插件的 priority 字段设置
阶段每个实例一个 phase一个模块可包含任意或全部六个阶段
上线控制跟随所挂载的资源部署到选定的网关组,可从测试环境逐步推广到生产环境
审查和治理在每个粘贴代码的资源中分别审查集中上传和版本管理,由 RBAC 治理
测试困难;逻辑是配置中的转义字符串可以作为模块测试(luac -p、路由测试)
运行时访问权限完整网关运行时完整网关运行时
最适合小型一次性代码片段和快速实验可复用、复杂的生产逻辑

两种机制使用相同权限运行,均不在沙箱中。无论选择哪种方式,都应同等谨慎地审查代码。

何时使用 Serverless 函数

Serverless 函数适用于以下逻辑:

  • 小且自包含——用几行代码设置请求头、调整变量或输出一行日志。
  • 特定于一个资源——预计不会在其他位置复用。
  • 快速实验——希望跳过上传和注册流程来试验某项功能。

何时使用自定义插件

只要逻辑不再简单,就应选择自定义插件,尤其是在需要以下能力时:

  • **配置。**使用带默认值且经过类型验证的 schema,让运维人员通过字段配置插件而非编辑 Lua。这是两种方式最大的实际差异。
  • **复用。**将一个具名插件应用到多个路由和服务,并在一个位置更新。
  • **受控上线。**先部署到测试网关组,验证后再添加生产网关组。参阅跨网关组上线
  • **多个阶段或特定优先级。**例如同时跨越 accesslog 的逻辑,或必须相对于其他插件在特定位置运行的逻辑。
  • **依赖项。**包路径中的共享辅助模块或原生库。参阅添加依赖库
  • **审查和生命周期管理。**使用集中上传、版本管理和 RBAC,避免代码散落在资源配置中。

复杂场景推荐使用自定义插件。它使逻辑更易复用、测试、配置和治理,而 Serverless 函数则让小型代码片段贴近其作用的资源。

后续步骤