API 网关专栏 · 第 32

API 网关如何实现自定义插件

2025年04月25日
API 网关如何实现自定义插件

简介

API 网关作为管理 API 流量的中心枢纽,提供诸如身份验证限流、可观测性和流量整形等功能。然而,开箱即用的功能可能无法覆盖所有的应用场景。这就是自定义插件发挥作用的地方。

自定义插件使开发者能够根据特定的业务或技术需求扩展 API 网关的功能。本文将探讨 API 网关中自定义插件的架构、开发、部署以及最佳实践。

为什么自定义插件很重要

应用场景

  • 业务逻辑执行:将特定的规则、策略或元数据注入到请求流程中。
  • 自定义身份验证:与内部身份验证系统或特定令牌格式进行集成。
  • 数据转换:修改请求/响应头或数据负载格式。
  • 监控:输出自定义指标或日志以实现可观测性。

优势

  • 更高的灵活性
  • 增强的可重用性
  • 模块化且易于维护的架构

API 网关中的插件架构

大多数 API 网关支持模块化的插件架构。这些插件作为请求生命周期的一部分执行,通常支持各个阶段:

  • 重写阶段 (Rewrite phase):在路由之前修改请求。
  • 访问阶段 (Access phase):执行身份验证或限流。
  • 负载均衡阶段 (Balancer phase):处理上游节点选择。
  • 头部过滤阶段 (Header filter phase):在发送响应前修改响应头。
  • 请求体过滤阶段 (Body filter phase):修改响应体。
  • 日志阶段 (Log phase):在请求结束后输出日志或指标。

插件生命周期

1sequenceDiagram
2    participant Client
3    participant Gateway
4    participant Plugin
5    participant Upstream
6    Client->>Gateway: 发送 API 请求
7    Gateway->>Plugin: 执行重写阶段
8    Gateway->>Plugin: 执行访问阶段
9    Gateway->>Upstream: 转发请求
10    Upstream-->>Gateway: 返回响应
11    Gateway->>Plugin: 执行头部过滤
12    Gateway->>Plugin: 执行请求体过滤
13    Gateway->>Plugin: 执行日志阶段
14    Gateway-->>Client: 返回最终响应

插件开发模型

Lua 插件(例如:Apache APISIX、Kong)

  • 优点:启动快、内存占用低、原生集成
  • 缺点:需要学习 Lua 语言
  • 示例:Apache APISIX
1-- sample.lua
2function _M.access(conf, ctx)
3    core.log.info("Custom plugin executing")
4    if ctx.var.uri == "/blocked" then
5        return 403, "Forbidden"
6    end
7end

Go 插件(例如:通过 Wasm 或 RPC 扩展的 APISIX)

  • 优点:强类型、生态丰富
  • 缺点:构建流水线较为复杂
  • 示例:
1func Access(ctx context.Context, request *apisix.Request) (*apisix.Response, error) {
2    if request.Path == "/custom" {
3        return apisix.Response{Status: 200, Body: "Handled by Go plugin"}, nil
4    }
5    return nil, nil
6}

JavaScript/Node.js 插件(例如:KrakenD、Express Gateway)

  • 优点:熟悉的语言、迭代速度快
  • 缺点:资源消耗较高

Wasm 插件(例如:Envoy、APISIX)

  • 优点:语言无关、沙盒化运行
  • 缺点:在某些网关中仍处于实验阶段

插件部署模型

进程内执行

插件在网关进程内执行,以实现低延迟。常见于 Lua 或嵌入式的 JavaScript 引擎。

外部执行 (通过 RPC)

插件作为外部服务运行,通过 gRPC、HTTP 或 Unix 域套接字进行通信。

  • 优点:隔离性好、支持多语言
  • 缺点:延迟略高、部署较为复杂

RPC 插件执行模型

1sequenceDiagram
2    participant Client
3    participant APISIX
4    participant PluginRunner
5    participant Java|Go|Node|Python
6
7    Client->>APISIX: 发送 HTTP/gRPC/MQTT 请求
8    APISIX->>APISIX: 应用全局规则(如:限流、安全策略)
9    APISIX->>APISIX: 路由匹配
10
11    Note over APISIX: 请求前置阶段
12    APISIX->>PluginRunner: ext-plugin-pre-req (RPC)
13    PluginRunner->>Java|Go|Node|Python: 执行 validator / rewrite-header / rewrite-args
14    Java|Go|Node|Python-->>PluginRunner: 返回结果
15    PluginRunner-->>APISIX: 返回预处理结果
16
17    APISIX->>APISIX: 应用路由级插件
18
19    Note over APISIX: 请求后置阶段
20    APISIX->>PluginRunner: ext-plugin-post-req (RPC)
21    PluginRunner->>Java|Go|Node|Python: 执行 rewrite-status / rewrite-header / rewrite-body
22    Java|Go|Node|Python-->>PluginRunner: 返回结果
23    PluginRunner-->>APISIX: 返回后置处理结果
24
25    APISIX->>Client: 返回最终响应

插件开发的最佳实践

设计指南

  • 保持插件无状态
  • 使用配置来实现逻辑分支
  • 限制在请求路径中进行密集的计算操作

测试

  • 独立地对核心逻辑进行单元测试
  • 使用网关的插件测试框架或基于 Docker 的测试工具

版本控制与兼容性

  • 锁定插件版本以避免破坏性变更
  • 遵循语义化版本控制并记录更新日志

安全

  • 严格验证输入参数
  • 避免任意代码执行漏洞
  • 利用网关的安全上下文(例如:沙盒机制)

总结

自定义插件对于根据特定需求量身定制 API 网关的行为至关重要。无论你是需要强制执行业务逻辑、扩展可观测性,还是与自定义的身份验证系统集成,编写和部署插件都能为你解锁强大的功能。

通过了解插件的生命周期、开发模型以及部署选项,工程师可以在保持性能和可靠性的同时,安全地扩展网关的功能。

常见问题 (FAQ)

1. 我应该使用哪种语言来编写自定义插件?

这取决于你的网关。Lua 在 APISIX 和 Kong 中非常流行,Envoy 支持 Wasm,而 KrakenD 支持 Go 和 JavaScript。

2. 自定义插件可以在不同网关之间移植吗?

通常不可以。每个网关都有自己特定的插件 API 和生命周期管理机制。

3. 插件会影响性能吗?

是的。编写不当的插件会拖慢请求处理速度。请务必测试并监控性能。

4. 如何调试自定义插件?

使用内置的日志记录、结构化的输出,以及网关提供的本地测试框架。

微信咨询

获取方案