Apache APISIX ext-plugin-pre-req 插件详解:在 Plugin Runner 中于内置 Lua 插件之前执行外部插件
2026/9/15 7:30:23 网站建设 项目流程

Apache APISIX ext-plugin-pre-req 插件详解:在 Plugin Runner 中于内置 Lua 插件之前执行外部插件

【免费下载链接】apisixThe Cloud-Native API Gateway项目地址: https://gitcode.com/GitHub_Trending/ap/apisix

ext-plugin-pre-req 是 Apache APISIX 中负责"外部插件调度"的入口插件之一,其职责是把当前请求交给独立的 Plugin Runner 进程(如 Go / Java / Python 编写的 Runner),在内置 Lua 插件执行之前完成外部插件的处理。本文将以官方文档为主体,结合 插件实现源码、RPC 通信核心 与 测试用例,完整讲解该插件的配置属性、启用/删除方法、底层 RPC 工作原理与降级机制,帮助你快速上手并理解外部插件体系。

插件是什么:执行时机与定位

ext-plugin-pre-req用于在Plugin Runner 中运行指定的外部插件,并且这些外部插件的执行时机早于 APISIX 内置的所有 Lua 插件。

它的定位可以从源码中的两个关键字段直接读出(apisix/plugins/ext-plugin-pre-req.lua):

  • priority = 12000:插件执行优先级。APISIX 按 priority 从大到小执行插件,12000 高于绝大多数内置插件(例如 key-auth 为 2500),因此该插件会最先拿到请求处理权;
  • rewrite阶段挂钩:插件在rewrite阶段调用ext.communicate(conf, ctx, name),将请求"转发"给外部 Runner 处理,并同步等待处理结果(详见下文"底层原理")。

与它配套的另外两个外部插件(conf/config.yaml.example 中可以看到三者默认注册)分别是:

插件priority挂载阶段作用
ext-plugin-pre-req12000rewrite在内置 Lua 插件之前运行外部插件,可修改请求
ext-plugin-post-req-3000access在请求阶段(access)之后运行外部插件,如对请求体做二次加工
ext-plugin-post-resp-4000access将上游响应交给外部插件处理,可改写响应头与响应体

:::note 外部插件执行会直接影响当前请求的行为(如修改请求头、请求体、URI,甚至直接终止请求并返回响应),配置前请确认外部插件逻辑符合预期。 :::

更完整的 Plugin Runner 架构与生态说明,可参阅仓库内的 external-plugin 文档。

Attributes 配置属性

插件的 Schema 定义在 apisix/plugins/ext-plugin/init.lua,与官方文档一致:

名称类型必填默认值有效值说明
confarray[{"name": "ext-plugin-A", "value": "{\"enable\":\"feature\"}"}]需要在 Plugin Runner 上执行的外部插件及其配置列表
allow_degradationbooleanfalse当 Plugin Runner 不可用时是否开启降级。设为true时允许请求继续(即忽略外部插件处理直接放行)

结合源码补充说明conf的校验细节:

  • 每个数组元素是一个对象,必须同时包含namevalue两个字段(required = {"name", "value"});
  • name为外部插件名,字符串类型,长度限制为1~128 个字符minLength = 1, maxLength = 128);
  • value为外部插件的配置,字符串类型,通常以 JSON 字符串形式传入(示例中的"{\"enable\":\"feature\"}"即一个 JSON 配置串);
  • 整个conf数组至少包含1 个元素minItems = 1),即至少要指定一个要执行的外部插件;
  • allow_degradation为布尔值,默认false

前置条件:先让 APISIX 认识 Plugin Runner

ext-plugin-pre-req本身不包含业务逻辑,它只是 APISIX 与 Plugin Runner 之间的"信使"。要让它生效,必须先配置 Plugin Runner。

生产环境:由 APISIX 托管 Runner

conf/config.yaml中加入以下配置,APISIX 会把 Runner 作为自己的子进程启动、管理与重启:

ext-plugin: cmd: ["/path/to/your/runner"] # 替换为实际 Runner 可执行文件路径

开发调试:Runner 独立运行

开发时往往希望单独启动 Runner、避免每次重启 APISIX,可通过环境变量APISIX_LISTEN_ADDRESS强制 Runner 监听固定地址:

APISIX_LISTEN_ADDRESS=unix:/tmp/x.sock ./the_runner

同时在config.yaml中让 APISIX 把 RPC 发往该固定地址:

ext-plugin: # cmd: ["blah"] # 独立运行模式下不要配置 cmd path_for_test: "/tmp/x.sock" # 注意不带 'unix:' 前缀

这条路径的解析逻辑在 apisix/plugins/ext-plugin/helper.lua:若配置了path_for_test则使用unix:前缀拼接该路径;否则默认使用动态生成的./conf/apisix-<master_pid>.sock。生产环境不应使用path_for_test

启用插件:在 Route 上绑定

下面示例为指定 Route 启用ext-plugin-pre-req插件(conf中声明了一个名为ext-plugin-A的外部插件及其 JSON 配置)。

:::note 先从config.yaml中取出admin_key并保存到环境变量,便于后续调用 Admin API:

admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')

:::

curl -i http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d ' { "uri": "/index.html", "plugins": { "ext-plugin-pre-req": { "conf" : [ {"name": "ext-plugin-A", "value": "{\"enable\":\"feature\"}"} ] } }, "upstream": { "type": "roundrobin", "nodes": { "127.0.0.1:1980": 1 } } }'

配置完成后,访问该路由的请求即会触发 APISIX 与 Plugin Runner 之间的 RPC 调用。

示例使用与验证

启用上述配置后,发起如下请求:

curl -i http://127.0.0.1:9080/index.html

该请求会到达已配置的 Plugin Runner,ext-plugin-A将在请求进入内置 Lua 插件阶段之前被依次执行,执行结果(可能包括改写后的请求头、URI,或直接生成的响应)会返回给 APISIX 继续处理。

仓库测试 t/plugin/ext-plugin/sanity.t 给出了同样的验证路径:先通过 Admin API 为/hello路由绑定带confext-plugin-pre-req,再发起GET /hello请求,并校验 Runner 端收到的 conf token 符合^route#1#ext-plugin-pre-req#模式——这印证了每个路由上每个外部插件都会在 Runner 侧生成独立的配置标识。

底层原理:RPC 通信与 Runner 生命周期

ext-plugin-pre-reqrewrite阶段调用的是 apisix/plugins/ext-plugin/init.lua 中的ext.communicate,其核心流程如下:

  1. 建立连接:通过 Unix Socket 连接 Plugin Runner(rpc_call),设置 1s 连接超时与 60s 读写超时,成功后复用连接(keepalive 180s)。
  2. PrepareConf(配置协商):首次请求时发送RPC_PREPARE_CONF,把conf数组中的外部插件名与配置逐项编码为 FlatBuffers 结构发送给 Runner;Runner 返回一个conf token。该 token 缓存在共享内存字典与 LRU 缓存中(token 缓存有效期见 helper.lua,默认 3600 秒),后续请求直接复用,避免重复协商。
  3. HTTPReqCall(请求调用):携带 token、方法、URI、查询参数、请求头、客户端地址等发起RPC_HTTP_REQ_CALL(init.lua)。期间 Runner 可通过RPC_EXTRA_INFO反向向 APISIX 询问 Nginx 变量、请求体、响应体等额外信息。
  4. 处理 Runner 的返回动作
    • Stop:外部插件直接终止请求,按 Runner 给定的状态码与响应体生成响应返回客户端(默认状态码 200);
    • Rewrite:把 Runner 改写后的 path、headers、args、body 写回当前请求(例如通过ngx.req.set_body_data替换请求体,改写upstream_uriupstream_host),并同步更新响应头。
  5. Runner 生命周期管理:Runner 由 privileged agent 进程以子进程方式拉起(init_worker),退出后 3 秒自动重新拉起,并在退出事件中清空 conf token 缓存;APISIX 退出时先发 SIGTERM、等待 1 秒后再强制结束(exit_worker)。

失败重试与降级行为

communicate内置最多 3 次重试(init.lua):

  • 若因 conf token 失效导致失败,会先刷新 token 缓存后重试;
  • 重试仍失败时,根据allow_degradation决定行为:
    • allow_degradation = true:记录 warning 并允许请求继续(跳过外部插件);
    • allow_degradation = false(默认):返回 HTTP503 Service Unavailable

环境变量传递

若 Runner 需要访问自定义环境变量,需先在conf/config.yamlnginx_config.envs中显式声明(Nginx 默认隐藏全部环境变量):

nginx_config: envs: - MY_ENV_VAR

删除插件

删除插件只需把对应 JSON 配置从 Route 的 plugins 中移除即可,APISIX 会自动热加载,无需重启

curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d ' { "uri": "/index.html", "upstream": { "type": "roundrobin", "nodes": { "127.0.0.1:1980": 1 } } }'

小结与注意事项

  • ext-plugin-pre-req(priority 12000)在 rewrite 阶段、早于内置 Lua 插件执行外部插件,与ext-plugin-post-req(-3000)、ext-plugin-post-resp(-4000)共同构成完整的外部插件处理链路;
  • conf数组元素必须包含name(1~128 字符)与value(配置 JSON 字符串),且至少一个元素;
  • 未配置 Plugin Runner 或 Runner 异常时,默认返回 503;通过allow_degradation: true可切换为放行降级模式;
  • 生产环境使用ext-plugin.cmd让 APISIX 托管 Runner,开发调试可用path_for_test+APISIX_LISTEN_ADDRESS固定通信地址;
  • 删除插件配置后热生效,无需重启 APISIX。

若希望进一步了解外部插件体系(Runner 的生态、实现细节与 FAQ),请继续阅读仓库内的 external-plugin 文档,并结合 RPC 核心实现 与 插件测试套件 深入探索。

【免费下载链接】apisixThe Cloud-Native API Gateway项目地址: https://gitcode.com/GitHub_Trending/ap/apisix

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询