Envoy gRPC-JSON 转码器功能实现分析

1. 概述

Envoy 的 gRPC-JSON 转码器功能为 HTTP/REST/JSON API 和 gRPC API 之间的双向转换提供了强大而灵活的解决方案。它允许开发人员利用 gRPC 的高性能和类型安全特性,同时保持与现有的 HTTP/JSON 客户端和工具的兼容性。它允许客户端使用熟悉的 JSON API 访问后端的 gRPC 服务,而不需要修改任何后端代码。

该功能的主要特点包括:

  1. 支持所有 gRPC 方法类型(一元、流式等)

  2. 提供了完整的错误处理和状态码转换

  3. 与 Envoy 的架构深度集成,性能优异

  4. 支持灵活的配置选项,包括打印格式、验证选项和路由级配置

  5. 与其他 Envoy 功能配合良好,如认证、路由和限流

通过合理配置 gRPC-JSON 转码器,您可以快速将现有的 gRPC 服务暴露为 RESTful API,或者将 HTTP/JSON 客户端与 gRPC 服务集成,提高了开发效率和系统的可维护性。

2. 解决的问题

gRPC-JSON 转码器功能主要解决以下问题:

2.1 API 兼容性

  • 允许客户端使用 HTTP/JSON API 访问 gRPC 服务,无需修改后端代码

  • 支持将 gRPC 服务自动转换为 RESTful API

  • 提供了与现有 HTTP 客户端和工具的兼容性

2.2 开发效率

  • 简化了前端开发,允许使用标准的 JSON API

  • 减少了编写和维护 HTTP 代理层的需求

  • 提供了自动的 API 文档生成支持

2.3 性能优化

  • 直接在 Envoy 层面进行转换,避免了额外的网络开销

  • 支持流式处理和双向通信

  • 提供了高效的序列化和反序列化机制

2.4 功能完整性

  • 支持所有 gRPC 方法类型,包括一元、服务器流式、客户端流式和双向流式

  • 自动处理 HTTP 头部和 gRPC 元数据之间的转换

  • 提供了错误处理和状态码转换

3. 架构设计

3.1 核心组件架构

3.2 类图

3. 配置用例

3.1 基础配置

bash 复制代码
http_filters:- name: envoy.filters.http.grpc_json_transcoder  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_json_transcoder.v3.GrpcJsonTranscoder    proto_descriptor: "/path/to/your/proto_descriptor_set.pb"    services: ["your.service.Name"]    print_options:      add_whitespace: true      always_print_enums_as_ints: false      always_print_primitive_fields: true  connect_timeout: 0.25s  lb_policy: ROUND_ROBIN

3.2 高级配置

bash 复制代码
http_filters:- name: envoy.filters.http.grpc_json_transcoder  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_json_transcoder.v3.GrpcJsonTranscoder    proto_descriptor: "/path/to/your/proto_descriptor_set.pb"    services: ["your.service.Name"]    print_options:      add_whitespace: true      always_print_enums_as_ints: false      always_print_primitive_fields: true    match_incoming_request_route: true    convert_grpc_status: true    ignore_unknown_query_parameters: true    request_validation_options:      reject_unknown_fields: true      reject_unknown_query_parameters: true

3.3 路由级配置

bash 复制代码
route_config:  name: local_route  virtual_hosts:  - name: backend    domains: ["*"]    routes:    - match:        prefix: "/api"      route:        cluster: grpc_backend        per_filter_config:          envoy.filters.http.grpc_json_transcoder:            "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_json_transcoder.v3.GrpcJsonTranscoder            proto_descriptor: "/path/to/your/proto_descriptor_set.pb"            services: ["your.service.Name"]            print_options:              add_whitespace: true

3.4 复杂配置

bash 复制代码
static_resources:  listeners:  - name: listener_0    address:      socket_address:        address: 0.0.0.0        port_value: 8080    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          stat_prefix: ingress_http          http_filters:          - name: envoy.filters.http.grpc_json_transcoder            typed_config:              "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_json_transcoder.v3.GrpcJsonTranscoder              proto_descriptor: "/path/to/your/proto_descriptor_set.pb"              services: ["your.service.Name"]              print_options:                add_whitespace: true                always_print_enums_as_ints: false                always_print_primitive_fields: true          - name: envoy.filters.http.router          route_config:            name: local_route            virtual_hosts:            - name: backend              domains: ["*"]              routes:              - match: { prefix: "/" }                route: { cluster: grpc_backend }  clusters:  - name: grpc_backend    connect_timeout: 0.25s    type: STRICT_DNS    lb_policy: ROUND_ROBIN    load_assignment:      cluster_name: grpc_backend      endpoints:      - lb_endpoints:        - endpoint:            address:              socket_address:                address: grpc-backend.example.com                port_value: 50051

4. 工作流程分析

4.1 过滤器执行流程

4.2 请求转换流程

5. 代码实现ER图

6. 最佳实践

6.1 性能优化

bash 复制代码
http_filters:- name: envoy.filters.http.grpc_json_transcoder  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_json_transcoder.v3.GrpcJsonTranscoder    proto_descriptor: "/path/to/your/proto_descriptor_set.pb"    services: ["your.service.Name"]    print_options:      add_whitespace: false      always_print_enums_as_ints: true      always_print_primitive_fields: true

6.2 安全性配置

bash 复制代码
http_filters:- name: envoy.filters.http.grpc_json_transcoder  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_json_transcoder.v3.GrpcJsonTranscoder    proto_descriptor: "/path/to/your/proto_descriptor_set.pb"    services: ["your.service.Name"]    request_validation_options:      reject_unknown_fields: true      reject_unknown_query_parameters: true

6.3 与其他过滤器配合使用

bash 复制代码
http_filters:- name: envoy.filters.http.jwt_authn  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication    providers:      # 认证配置- name: envoy.filters.http.grpc_json_transcoder  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_json_transcoder.v3.GrpcJsonTranscoder    proto_descriptor: "/path/to/your/proto_descriptor_set.pb"    services: ["your.service.Name"]- name: envoy.filters.http.router

6.4 多服务配置

bash 复制代码
http_filters:- name: envoy.filters.http.grpc_json_transcoder  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_json_transcoder.v3.GrpcJsonTranscoder    proto_descriptor: "/path/to/your/proto_descriptor_set.pb"    services: ["your.service1.Name", "your.service2.Name"]

7. 代码实现细节

7.1 过滤器初始化

css 复制代码
JsonTranscoderFilter::JsonTranscoderFilter(JsonTranscoderConfig& config)     : config_(config), transcoder_(nullptr), method_(nullptr) {}

7.2 转码器创建

php 复制代码
void JsonTranscoderFilter::initPerRouteConfig() {  const auto* route_config = Http::Utility::resolveMostSpecificPerFilterConfig<JsonTranscoderConfig>(      *decoder_callbacks_);
  if (route_config != nullptr) {    per_route_config_ = route_config;  } else {    per_route_config_ = &config_;  }}
Http::FilterHeadersStatus JsonTranscoderFilter::decodeHeaders(Http::RequestHeaderMap& headers, bool) {  initPerRouteConfig();  if (per_route_config_->disabled()) {    return Http::FilterHeadersStatus::Continue;  }
  auto status = per_route_config_->createTranscoder(      headers, request_in_, response_in_, transcoder_, method_);
  if (!status.ok()) {    if (status.error_code() == ProtobufUtil::StatusCode::NOT_FOUND) {      return Http::FilterHeadersStatus::Continue;    }
    return checkAndRejectIfRequestTranscoderFailed(status.ToString());  }
  // 配置转码器  const auto& request_info = headers;  if (transcoder_ != nullptr) {    // 初始化请求转换  }
  return Http::FilterHeadersStatus::Continue;}

7.3 请求处理

php 复制代码
Http::FilterDataStatus JsonTranscoderFilter::decodeData(Buffer::Instance& data, bool end_stream) {  if (per_route_config_->disabled() || transcoder_ == nullptr) {    return Http::FilterDataStatus::Continue;  }
  if (!first_request_sent_) {    // 处理初始请求数据    first_request_sent_ = true;    maybeSendHttpBodyRequestMessage();  }
  // 处理请求数据  request_data_.add(data);  if (decoderBufferLimitReached(request_data_.length())) {    return Http::FilterDataStatus::StopIterationNoBuffer;  }
  if (end_stream) {    // 处理请求结束  }
  return Http::FilterDataStatus::Continue;}

7.4 响应处理

php 复制代码
Http::FilterDataStatus JsonTranscoderFilter::encodeData(Buffer::Instance& data, bool end_stream) {  if (per_route_config_->disabled() || transcoder_ == nullptr) {    return Http::FilterDataStatus::Continue;  }
  response_in_.add(data);
  if (hasHttpBodyAsOutputType()) {    if (!http_body_response_headers_set_) {      response_headers_->setReferenceContentType(content_type_);      http_body_response_headers_set_ = true;      encoder_callbacks_->encodeHeaders(*response_headers_, false);    }
    if (buildResponseFromHttpBodyOutput(*response_headers_, data)) {      if (end_stream) {        // 发送响应结束      }      return Http::FilterDataStatus::Continue;    }  }
  return Http::FilterDataStatus::StopIterationAndBuffer;}
相关推荐
terry60018 小时前
从流畅交互到高可用:企讯通Qcaptcha滑动拼图的毫秒级响应与容灾设计
web安全·json·asp.net·信息与通信·数据库架构
terry6001 天前
2026企业级携号转网查询标准:论实时数据同步与高并发承载设计
java·大数据·人工智能·json·信息与通信·数据库架构
㱘郳2 天前
VS Code 的setting.json的预配置
json
一拳小和尚LXY2 天前
我开发了一款免费 Chrome 插件 TabScribe:一键复制所有标签页为 Markdown/JSON,完全离线零追踪
前端·chrome·json
nap-joker2 天前
使用n8n+飞书搭建自动推送新闻机器人
javascript·json·飞书·工作流·n8n·36氪新闻向客户端推送
一只积极向上的小咸鱼2 天前
TOML、JSON、YAML、INI 配置文件格式总结
java·服务器·json
San813_LDD2 天前
[后端开发]GET/POST_带参/不带参
前端·后端·计算机网络·json
winfredzhang2 天前
Python 实战:用 wxPython 写一个 MD5 文件查重清理工具
python·sqlite·json·wxpython·md5·预览·查重
木雷坞3 天前
6月 Docker 国内镜像源配置:daemon.json、/v2/ 连通性和 pull 验证
docker·eureka·json
落羽的落羽3 天前
【项目】JsonRpc框架——开发实现2(业务层)
linux·数据结构·c++·人工智能·算法·json·动态规划