
Envoy gRPC HTTP/1.1 Reverse Bridge 过滤器实战让 gRPC 客户端对接纯 HTTP/1.1 上游服务【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy本文围绕 Envoy 的envoy.filters.http.grpc_http1_reverse_bridgeHTTP 过滤器展开系统讲解它如何将下游 gRPC 请求降级为普通 HTTP/1.1 请求转发给上游再把上游的 HTTP 响应还原成 gRPC 响应返回客户端。读完本文你将掌握该过滤器的工作原理、withhold_grpc_frames帧头管理机制、response_size_header流式响应配置以及如何按路由Route粒度精细控制过滤器的启停从而让不支持 HTTP/2 / HTTP/3 与 gRPC 语义的老旧服务平滑接入 gRPC 生态。过滤器定位为不支持 gRPC 的服务做协议翻译gRPC 基于 HTTP/2 承载并依赖application/grpc内容类型、5 字节帧头1 字节压缩标志 4 字节消息长度以及结尾的grpc-statustrailer 等特有语义。很多存量服务只支持 HTTP/1.1 与普通的 Protobuf 二进制消息无法直接作为 gRPC 上游工作。gRPC HTTP/1.1 Reverse Bridge 过滤器正是为解决这一鸿沟而生它把传入的 gRPC 请求转换为 HTTP/1.1 请求让一个不理解 HTTP/2、HTTP/3 或 gRPC 语义的服务器也能正常处理该请求响应路径上再做逆向转换把普通 HTTP 响应包装回客户端期望的 gRPC 响应。从源码结构看该过滤器是一个标准的 Envoy 流式 HTTP 过滤器Stream Filter类型为 Filter通过 Config 工厂 以名称envoy.filters.http.grpc_http1_reverse_bridge静态注册REGISTER_FACTORY配置类型为type.googleapis.com/envoy.extensions.filters.http.grpc_http1_reverse_bridge.v3.FilterConfig。工作流程请求与响应两个方向的四步转换根据官方文档与 filter.cc 的实现过滤器在请求解码与响应编码两个方向共完成以下步骤请求方向Downstream → Upstream识别 gRPC 请求检查入站请求的content-type。若命中 gRPC 请求Envoy::Grpc::Common::isGrpcRequestHeaders判定成功则启用过滤器同时记录原始 content-type兼容application/grpcproto等变体并把 content-type 改写为配置项content_type指定的值。改写内容类型将请求的content-type与Accept头统一设置为配置值见 filter.cc#L98-L105。若该值配置为application/grpc则等价于 noop不改变原始语义。可选剥离 gRPC 帧头若开启withhold_grpc_frames从请求体中剥掉 5 字节的 gRPC 帧头并同步调整content-length见 filter.cc#L107-L110。帧头剥离只执行一次prefix_stripped_标志位保证。刷新路由缓存clearRouteCache()允许请求被改写后重新参与路由计算提供更大的路由灵活性见 filter.cc#L114。响应方向Upstream → Downstream校验上游 content-type若上游响应头中的 content-type 与配置的content_type不一致直接以 HTTP 200 返回错误grpc-message中携带详细错误信息grpc-status置为Unknown见 filter.cc#L142-L150。还原 content-type把响应头恢复为下游请求最初携带的 gRPC content-type见 filter.cc#L153。状态码映射将上游 HTTP 状态码映射为grpc-status并记入响应 trailer。特别地上游返回 200 视为grpc-status: 0 (Ok)非 200 状态码通过Grpc::Utility::httpToGrpcStatus转换见 filter.cc#L40-L51。固定 HTTP 状态为 200gRPC 客户端总是期望 HTTP 状态码为 200真正的错误信息通过grpc-statustrailer 传递因此响应状态被强制改写为 200见 filter.cc#L206-L207。可选回填 gRPC 帧头若开启withhold_grpc_frames在响应体前重新注入 5 字节 gRPC 帧头并相应调整content-length。注意由于最终映射为 HTTP/1.1该过滤器只适用于 unary一元gRPC 调用不适用于流式streamingRPC。gRPC 帧头管理withhold_grpc_frames 的两种上游协作模式gRPC 数据帧的固定 5 字节头1 字节压缩标志 4 字节大端消息长度是上游服务处理 gRPC 消息的主要负担。withhold_grpc_frames参数决定是否把这层 gRPC 语义对上游隐藏withhold_grpc_frames: true推荐对上游最友好Envoy 假定上游完全不理解 gRPC 语义。请求方向剥离 gRPC 帧头将请求体变成纯二进制 Protobuf 编码转发给上游响应方向由 Envoy 负责注入 gRPC 帧头。上游服务只需处理一个请求体就是一个完整 Protobuf 消息的简单二进制格式无需关心帧解析与帧生成见 filter.cc#L120-L133 的剥离逻辑与 filter.cc#L295-L302 的帧头构建逻辑。withhold_grpc_frames: false上游需理解 gRPC上游必须准备好接收带 gRPC 帧头前缀的 HTTP/1.1 请求并以 gRPC 格式化数据含帧头响应。一个小限制当withhold_grpc_frames为 true 且未配置response_size_header时为了在响应端计算正确的content-length与帧大小Envoy 需要先缓冲完整的上游响应见 filter.cc#L266-L274这在大响应场景下会带来内存开销response_size_header可以规避缓冲详见下文。配置详解FilterConfig 全部参数过滤器配置定义在 config.proto核心消息为FilterConfig参数类型必填说明content_typestring是min_len: 1转发给上游时使用的 content-type同时用于校验上游响应必须携带相同的 content-type。配置为application/grpc可视为 noopwithhold_grpc_framesbool否默认false为 true 时 Envoy 假定上游不理解 gRPC 帧请求剥帧头、响应补帧头隐藏全部 gRPC 语义response_size_headerstring否默认空仅当withhold_grpc_frames为 true 时生效。非空时Envoy 改为流式转发响应并使用该名称的上游响应头值来设置content-length与 gRPC 帧大小该头重复出现时只取第一个值。若头缺失或值与实际响应体大小不符Envoy 将把上游响应视为错误response_size_header的取值受HTTP_HEADER_NAME规则校验见 config.proto#L50-L51。上游返回该头后Envoy 会在响应端把content-length调整为消息长度 5 字节帧头见 filter.cc#L155-L174。同时源码还限制了单个 Protobuf 消息不能超过 2GBuint32_t上限超出即报错见 filter.cc#L183-L190。若上游同时提供了标准Content-Length头且未配置response_size_headerEnovy 也会借其实现流式转发避免一次性把整个响应体压给 HTTP/2 codec 造成大量帧同时下发见 filter.cc#L175-L194。完整配置示例官方 YAML以下配置来自仓库中的 grpc-reverse-bridge-filter.yaml演示了过滤器在 HTTP Connection Manager 中的标准挂载方式以及按路由启用/禁用的完整形态admin: address: socket_address: address: 0.0.0.0 port_value: 9901 static_resources: listeners: - name: listener_0 address: socket_address: address: 0.0.0.0 port_value: 80 filter_chains: - filters: - name: envoy.filters.network.http_connection_manager typed_config: type: type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager access_log: - name: envoy.access_loggers.stdout typed_config: type: type.googleapis.com/envoy.access_loggers.stream.v3.StdoutAccessLog stat_prefix: ingress_http route_config: name: local_route virtual_hosts: - name: local_service domains: [*] routes: - match: prefix: /route-with-filter-disabled route: host_rewrite_literal: localhost cluster: grpc timeout: 5.00s # per_filter_config disables the filter for this route typed_per_filter_config: envoy.filters.http.grpc_http1_reverse_bridge: type: type.googleapis.com/envoy.extensions.filters.http.grpc_http1_reverse_bridge.v3.FilterConfigPerRoute disabled: true - match: prefix: /route-with-filter-enabled route: host_rewrite_literal: localhost cluster: other timeout: 5.00s http_filters: - name: envoy.filters.http.grpc_http1_reverse_bridge typed_config: type: type.googleapis.com/envoy.extensions.filters.http.grpc_http1_reverse_bridge.v3.FilterConfig content_type: application/grpcproto withhold_grpc_frames: true - name: envoy.filters.http.router typed_config: type: type.googleapis.com/envoy.extensions.filters.http.router.v3.Router clusters: - name: other type: LOGICAL_DNS dns_lookup_family: V4_ONLY lb_policy: ROUND_ROBIN load_assignment: cluster_name: some_service endpoints: - lb_endpoints: - endpoint: address: socket_address: address: localhost port_value: 4630 - name: grpc type: STRICT_DNS lb_policy: ROUND_ROBIN typed_extension_protocol_options: envoy.extensions.upstreams.http.v3.HttpProtocolOptions: type: type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions explicit_http_config: http2_protocol_options: {} load_assignment: cluster_name: grpc endpoints: - lb_endpoints: - endpoint: address: socket_address: address: localhost port_value: 10005要点提示过滤器在http_filters链中必须置于envoy.filters.http.router之前与所有转换型过滤器一致上例中content_type设为application/grpcproto即上游收到的请求与返回的响应都携带该 content-type同时withhold_grpc_frames: true保证上游只看到纯二进制 Protobuf 体演示了两种集群other普通 HTTP/1.1 上游端口 4630与grpc显式配置 HTTP/2 协议选项的上游端口 10005分别对应启用与禁用该过滤器的路由。按路由禁用过滤器FilterConfigPerRoute实际部署中同一个监听器下往往同时存在需要桥接和不需要桥接的路径。FilterConfigPerRoute提供了路由级开关在 Route或 VirtualHost / WeightedCluster上通过typed_per_filter_config挂载该配置将disabled置为true即可让该路由跳过桥接逻辑见上例中/route-with-filter-disabled路由。FilterConfigPerRoute的 proto 定义见 config.proto#L55-L62只有一个bool disabled字段若在多处 per-filter-config 中同时指定则以最具体的一处为准。实现上过滤器在decodeHeaders阶段通过Http::Utility::resolveMostSpecificPerFilterConfig解析路由级配置一旦发现disabled即置enabled_ false并直接放行后续编解码路径全部跳过见 filter.cc#L86-L93。源码级原理关键错误处理与边界行为从 filter.h 与 filter.cc 可以归纳出过滤器内置的几类防御性错误处理RcDetails中定义的明细编码会出现在 Envoy 的请求失败详情中明细值触发条件处理方式grpc_bridge_data_too_small请求体不足 5 字节不可能构成合法 gRPC 帧HTTP 200 grpc-status: Unknowngrpc-message: invalid request body见 filter.cc#L122-L128grpc_bridge_content_type_wrong上游响应 content-type 与配置不一致或缺失 content-typeHTTP 200 grpc-status: Unknowngrpc-message携带上游实际 content-type 与状态码见 filter.cc#L142-L150grpc_bridge_content_length_missing配置了response_size_header但上游未返回该头HTTP 200 grpc-status: Internal见 filter.cc#L166-L173grpc_bridge_content_length_wrongresponse_size_header或上游Content-Length与实际响应体大小不符或响应超过 2GBHTTP 200 grpc-status: Internal见 filter.cc#L183-L190 与 filter.cc#L249-L256其他值得注意的边界行为Header-only 请求无请求体过滤器直接放行、不做任何改写见 filter.cc#L80-L83Header-only 响应直接构造一个长度为 0 的 gRPC 帧buildGrpcFrameHeader(data, 0)并把content-length精确设置为 5同时补上grpc-statustrailer见 filter.cc#L211-L223非 gRPC 请求即使content-type是application/grpc以外的普通类型过滤器全程透传、零改写enabled_保持 false。测试验证从单测到集成测试仓库为该过滤器提供了三层测试保障可作为行为规范spec阅读reverse_bridge_test.cc1154 行的单元测试覆盖非法小请求体直接失败断言 HTTP 200 grpc-status: 2与明细grpc_bridge_data_too_small、header-only 请求不被改写、非 gRPC 请求透传、content-length从 25 调整为 20剥离 5 字节帧头等核心行为config_test.cc验证FilterConfig与FilterConfigPerRoute两种配置均能被工厂正确解析并注册为流式过滤器与路由级配置对象reverse_bridge_integration_test.cc端到端集成测试验证真实 Envoy 实例在启停该过滤器时的完整请求/响应链路。适用边界与总结适用场景gRPC 客户端需要调用仅支持 HTTP/1.1 纯 Protobuf 的存量服务或希望统一以 gRPC 暴露 API但后端尚未完成 HTTP/2 改造的过渡期。明确限制仅支持unary gRPCstreaming RPC 会因 HTTP/1.1 映射而无法工作启用withhold_grpc_frames且未配置response_size_header时响应会被整体缓冲注意大响应下的内存水位单个响应消息不得超过 2GB上游必须严格遵守配置的content_type返回响应否则会被判定为错误。总体而言gRPC HTTP/1.1 Reverse Bridge 是 Envoy 协议转换能力中面向存量系统兼容的务实组件通过 FilterConfig 的content_type、withhold_grpc_frames、response_size_header三个旋钮配合路由级disabled开关即可在不改动上游服务的前提下让 gRPC 流量安全地落到任何支持 HTTP/1.1 的服务器上。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考