You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Envoy json_to_metadata扩展基于请求体路由失败排查求助

基于Envoy Proxy根据POST请求体路由请求的问题排查

需求

针对POST /v2/meal接口,请求体包含"food":"fruit"时路由至Service A,包含"food":"soup"时路由至Service B。

实现配置

Envoy过滤器配置

添加json_to_metadata过滤器解析请求体并写入元数据,同时配置访问日志记录元数据:

resources:
  - name: listener_0
    "@type": type.googleapis.com/envoy.config.listener.v3.Listener
    traffic_direction: INBOUND
    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
            access_log: # 记录请求日志
              - name: envoy.access_loggers.typed_json
                typed_config:
                  "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
                  path: "/dev/stdout"
                  typed_json_format:
                    message: "requestLog"
                    # 省略其他字段
                    meta_data: "%DYNAMIC_METADATA(envoy.lb)%" # 元数据字段始终为null
            http_filters:
            - name: envoy.filters.http.json_to_metadata
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.http.json_to_metadata.v3.JsonToMetadata
                request_rules:
                  rules:
                  - selectors:
                    - key: food
                    on_present:
                      metadata_namespace: envoy.lb
                      key: food
                    on_missing:
                      metadata_namespace: envoy.lb
                      key: default
                      value: "foodMissing"
                      preserve_existing_metadata_value: true
                    on_error:
                      metadata_namespace: envoy.lb
                      key: default
                      value: "foodError"
                      preserve_existing_metadata_value: true
            - name: envoy.filters.http.router # 必须是HTTP过滤器链的最后一个
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

Python动态路由配置

使用envoy_data_plane构建路由,通过MetadataMatcher匹配元数据中的food值:

# 根据请求体中的food字段路由
metadata_matchers = []
if route_data.get("food"):
    food = route_data.get("food")
    metadata_matchers.append(MetadataMatcher(
        filter="envoy.lb",
        path=[
            MetadataMatcherPathSegment("food")
        ],
        value=ValueMatcher(
            string_match=StringMatcher(
                exact=food,
                ignore_case=True
            )
        )
    ))
route_match = RouteMatch(
    dynamic_metadata=metadata_matchers, # 匹配元数据
    prefix=request_path_prefix,
    case_sensitive=False,
    headers=request_headers,
    query_parameters=query_parameters
)

路由规则定义:

ROUTES = [
    {
        "prefix": "/v2/meal",
        "food": "fruit",
        "config": SERVICE_A
    },
    {
        "prefix": "/v2/meal",
        "food": "soup",
        "config": SERVICE_B
    },
]

问题现象

使用命令curl -X POST localhost:8080/v2/meal --data-raw '{"food":"fruit"}'测试时,返回404错误,请求被路由至默认集群Service C(该集群无/v2/meal接口),且访问日志中meta_data字段为null:

{"response_code":404,"request_method":"POST","trace_id":null,"user_agent":"curl/8.4.0","message":"requestLog","protocol":"HTTP/1.1","authority":"localhost:8080","full_path":"/v2/meal","bytes_sent":0,"timestamp":"2024-02-12T22:14:36.573Z","request_id":"fe632ad6-f9a7-4349-a6bc-22fd09e76b5d","duration":285,"cluster":"SERVICE_C","meta_data":null,"upstream_service_time":null,"bytes_received":164,"response_flags":"-"}

排查与修复建议

  1. 添加Content-Type请求头
    json_to_metadata过滤器默认仅处理Content-Type: application/json的请求,测试命令需补充该头:

    curl -X POST localhost:8080/v2/meal -H "Content-Type: application/json" --data-raw '{"food":"fruit"}'
    

    若需要支持其他Content-Type,可在过滤器配置中添加match_content_type字段指定额外类型。

  2. 验证元数据写入与日志输出
    修改访问日志格式,单独输出food元数据字段,确认过滤器是否正常写入:

    typed_json_format:
      # 其他字段省略
      food_meta: "%DYNAMIC_METADATA(envoy.lb:food)%"
      default_meta: "%DYNAMIC_METADATA(envoy.lb:default)%"
    

    若输出foodError,说明请求体JSON解析失败;输出foodMissing说明未匹配到food字段;若仍为null,检查过滤器是否被正确加载(可通过Envoy admin接口/config_dump查看过滤器配置)。

  3. 调整路由匹配顺序
    Envoy路由按配置顺序匹配,确保带有元数据匹配的路由(Service A、Service B)排在默认路由(Service C)之前,避免默认路由先被匹配。

  4. 确认元数据匹配配置正确性
    检查MetadataMatcher的参数:

    • filter字段需与过滤器配置的metadata_namespace一致(此处为envoy.lb)
    • path需正确指向元数据中的字段路径(此处顶级字段food,路径配置正确)
    • 可通过Envoy admin接口/routes查看生成的路由配置,确认元数据匹配规则已正确生成。
  5. 版本兼容性检查
    确认使用的Envoy版本支持json_to_metadata过滤器(v1.18及以上版本支持),且envoy_data_plane生成的配置符合对应Envoy版本的v3 API规范。

内容的提问来源于stack exchange,提问作者Kai W

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 04:11:00