使用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
相关产品推荐
相关产品推荐

