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

使用Protobuf接收JSON反序列化为map[string]any时变量为空的问题

问题原因

你发送的JSON中variables字段是普通键值对对象,但google.protobuf.Struct在gRPC-JSON规范中要求以fields嵌套的结构表示,直接发送普通对象会导致反序列化器无法识别,最终Variables的字段为空。

解决方案

以下是三种可行的解决方式,可根据你的场景选择:

方式一:修改Proto定义,使用map<string, google.protobuf.Value>替代Struct

这是对客户端最友好的方案,无需修改客户端发送的JSON格式:

import "google/protobuf/struct.proto";

service Renderer {
  rpc Render(Request) returns (Response) {}
}

message Request {
  string template = 1;
  string locale = 2;
  map<string, google.protobuf.Value> variables = 3;
}

生成Go代码后,可直接将Value类型转换为Go原生类型使用:

func (s *Server) Render(
    ctx context.Context,
    message *Request,
) (*Response, error) {
    variablesMap := make(map[string]any, len(message.Variables))
    for k, v := range message.Variables {
        variablesMap[k] = v.AsInterface()
    }
    fmt.Println(variablesMap) // 输出: map[foo:bar]
    return &Response{}, nil
}

方式二:客户端按照gRPC-JSON规范发送Struct格式的JSON

若必须保留google.protobuf.Struct类型,客户端需调整JSON结构,将值嵌套在对应类型字段中:

{
    "template": "template_name",
    "locale": "pt",
    "variables": {
        "fields": {
            "foo": {
                "stringValue": "bar"
            }
        }
    }
}

此方案无需修改服务端代码,客户端按规范发送即可。

方式三:服务端手动适配普通JSON到Struct

若无法修改客户端和Proto定义,可在服务端手动解析原始请求体,将普通JSON对象转换为structpb.Struct:

import (
    "encoding/json"
    "google.golang.org/protobuf/types/known/structpb"
)

func (s *Server) Render(
    ctx context.Context,
    message *Request,
) (*Response, error) {
    // 假设通过上下文获取原始请求体字节(需根据实际框架调整)
    rawBody := []byte(`{"template":"template_name","locale":"pt","variables":{"foo":"bar"}}`)
    
    var rawReq map[string]any
    if err := json.Unmarshal(rawBody, &rawReq); err != nil {
        return nil, err
    }
    
    variablesBytes, err := json.Marshal(rawReq["variables"])
    if err != nil {
        return nil, err
    }
    
    var variables structpb.Struct
    if err := structpb.UnmarshalJSON(variablesBytes, &variables); err != nil {
        return nil, err
    }
    
    message.Variables = &variables
    fmt.Println(message.Variables.AsMap()) // 输出: map[foo:bar]
    return &Response{}, nil
}

内容的提问来源于stack exchange,提问作者Eleandro Duzentos

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 05:53:27