3. Envoy HTTP 过滤器扩展机制:生命周期、回调与工厂模式
Envoy 的 HTTP 过滤器扩展机制是构建可编程七层网关的核心。理解过滤器的生命周期、回调接口以及配置解析的工厂模式,是开发自定义扩展的前提。本章将深入剖析这些底层机制,为后续集成策略即代码(Policy as Code)资源配额模型奠定基础。
3.1 HTTP Filter 生命周期
每个 HTTP 过滤器实例都遵循一个严格的生命周期,从创建到销毁,确保资源被正确管理。生命周期由 Envoy 的 FilterChain 管理,并在 Worker 线程中执行。
核心阶段: 初始化 → 配置加载 → 回调注册 → 请求处理 → 销毁
| 阶段 | 触发时机 | 关键行为 |
|---|---|---|
| 1. 工厂创建 | Listener 配置加载时 | Envoy 根据配置中的 typed_config 或 config 字段,调用对应的 NamedHttpFilterConfigFactory 创建过滤器实例。 |
| 2. 配置解析 | 工厂创建后立即执行 | 工厂解析 Protobuf 配置消息,生成不可变的 FilterConfig 对象。 |
| 3. 实例化 | 每个新 HTTP 请求/流开始时 | 工厂为每个请求流创建一个新的 StreamFilter 实例,传入 FilterConfig 和 FilterCallbacks。 |
| 4. 请求处理 | 请求/响应生命周期内 | 过滤器通过 Decoder/Encoder 回调处理数据,并调用 FilterCallbacks 与下游/上游交互。 |
| 5. 销毁 | 请求/流结束后 | Envoy 自动销毁 StreamFilter 实例,释放关联资源(如定时器、连接池引用)。 |
3.2 Stream / Decoder / Encoder 回调
Envoy 的 HTTP 过滤器基于 Stream 模型,将请求和响应处理拆分为 Decoder(解码器,处理入站数据)和 Encoder(编码器,处理出站数据)两个方向。过滤器通过实现特定的回调接口来介入数据处理。
3.2.1 核心回调接口
| 接口 | 方向 | 主要回调方法 | 用途 |
|---|---|---|---|
StreamDecoderFilter |
请求(下游 → 上游) | decodeHeaders(), decodeData(), decodeTrailers() |
拦截、修改或终止请求头、体和尾部。 |
StreamEncoderFilter |
响应(上游 → 下游) | encodeHeaders(), encodeData(), encodeTrailers() |
拦截、修改或终止响应头、体和尾部。 |
StreamFilterBase |
双向 | onDestroy() |
流销毁时的清理回调。 |
3.2.2 回调执行顺序
在一个典型的请求-响应周期中,回调的执行顺序如下:
- 请求阶段(Decoder):
decodeHeaders()→decodeData()(可能多次) →decodeTrailers()(可选)。 - 上游处理: Envoy 将请求转发给上游集群。
- 响应阶段(Encoder):
encodeHeaders()→encodeData()(可能多次) →encodeTrailers()(可选)。 - 流结束:
onDestroy()被调用。
最佳实践: 在
decodeHeaders() 中执行策略决策(如配额检查),因为此时可以高效地拒绝请求,避免不必要的上游连接和数据传输。
3.3 配置解析与工厂模式
Envoy 使用 工厂模式 来解耦过滤器的配置定义与实例创建。每个过滤器扩展必须实现 NamedHttpFilterConfigFactory 接口,该接口负责解析 Protobuf 配置并生成过滤器实例。
3.3.1 工厂接口核心方法
| 方法 | 职责 | 返回值 |
|---|---|---|
createFilterFactoryFromProto() |
解析 Protobuf 配置消息,返回一个工厂函数。 | FilterFactoryCb(回调函数) |
createFilterFactoryFromProtoTyped() |
解析类型化的 Protobuf 配置(推荐方式)。 | FilterFactoryCb |
name() |
返回过滤器的唯一名称(如 envoy.filters.http.my_filter)。 |
std::string |
configType() |
返回配置消息的 Protobuf 描述符。 | ProtobufTypes::MessagePtr |
3.3.2 配置解析流程
- 配置加载: Envoy 读取静态或动态 xDS 配置,找到 HTTP 过滤器列表。
- 工厂查找: 根据过滤器名称(如
envoy.filters.http.quota),在注册的工厂映射表中查找对应的NamedHttpFilterConfigFactory。 - 配置反序列化: 调用
createFilterFactoryFromProtoTyped(),将typed_config中的 JSON/YAML 反序列化为具体的 Protobuf 配置对象。 - 配置验证: 工厂对配置进行语义验证(如检查必填字段、值范围)。
- 工厂函数生成: 返回一个
FilterFactoryCb,该回调在每次新请求到来时被调用,用于创建StreamFilter实例。
注意: 配置对象(
FilterConfig)在工厂创建后即被共享,必须是不可变的(const)。任何可变状态都应放在请求级别的 StreamFilter 实例中。
3.3.3 代码示例:工厂模式骨架
// 1. 定义 Protobuf 配置(.proto 文件)
message MyFilterConfig {
string policy_name = 1;
uint32 max_quota = 2;
}
// 2. 实现工厂类
class MyFilterFactory : public Server::Configuration::NamedHttpFilterConfigFactory {
public:
// 返回过滤器名称
std::string name() const override {
return "envoy.filters.http.my_filter";
}
// 返回配置类型
ProtobufTypes::MessagePtr createEmptyConfigProto() override {
return std::make_unique<MyFilterConfig>();
}
// 核心工厂方法
Http::FilterFactoryCb createFilterFactoryFromProtoTyped(
const MyFilterConfig& proto_config,
const std::string& stats_prefix,
Server::Configuration::FactoryContext& context) override {
// 解析并验证配置
auto shared_config = std::make_shared<MyFilterConfig>(proto_config);
// 返回工厂回调
return [shared_config](Http::FilterChainFactoryCallbacks& callbacks) {
// 每次请求创建新的 StreamFilter
auto filter = std::make_shared<MyStreamFilter>(shared_config);
callbacks.addStreamDecoderFilter(filter);
};
}
};
3.4 本章小结
- 生命周期: 过滤器遵循“工厂创建 → 配置解析 → 实例化 → 请求处理 → 销毁”的严格流程,确保线程安全与资源隔离。
- 回调机制:
StreamDecoderFilter和StreamEncoderFilter分别处理请求和响应,onDestroy()负责清理。 - 工厂模式: 通过
NamedHttpFilterConfigFactory解耦配置与实例化,配置不可变,实例按需创建。 - 扩展点: 开发者只需实现回调接口和工厂类,即可将自定义逻辑无缝集成到 Envoy 的 HTTP 处理管道中。