我写了一个简单的 GRPC 服务器和一个调用服务器的客户端(都在 Go 中)。请告诉我使用 golang/protobuf/struct 是否是使用 GRPC 发送动态 JSON 的最佳方式。
在下面的示例中,我之前将 Details
创建为 map[string]interface{}
并将其序列化。然后我将它作为 bytes
在 protoMessage 中发送,并在服务器端反序列化消息。
这是最好/最有效的方法还是我应该在我的原型(prototype)文件中将 Details 定义为一个结构?
下面是User.proto文件
syntax = "proto3";
package messages;
import "google/protobuf/struct.proto";
service UserService {
rpc SendJson (SendJsonRequest) returns (SendJsonResponse) {}
}
message SendJsonRequest {
string UserID = 1;
google.protobuf.Struct Details = 2;
}
message SendJsonResponse {
string Response = 1;
}
下面是client.go文件
package main
import (
"context"
"flag"
pb "grpc-test/messages/pb"
"log"
"google.golang.org/grpc"
)
func main() {
var serverAddr = flag.String("server_addr", "localhost:5001", "The server address in the format of host:port")
opts := []grpc.DialOption{grpc.WithInsecure()}
conn, err := grpc.Dial(*serverAddr, opts...)
if err != nil {
log.Fatalf("did not connect: %s", err)
}
defer conn.Close()
userClient := pb.NewUserServiceClient(conn)
ctx := context.Background()
sendJson(userClient, ctx)
}
func sendJson(userClient pb.UserServiceClient, ctx context.Context) {
var item = &structpb.Struct{
Fields: map[string]*structpb.Value{
"name": &structpb.Value{
Kind: &structpb.Value_StringValue{
StringValue: "Anuj",
},
},
"age": &structpb.Value{
Kind: &structpb.Value_StringValue{
StringValue: "Anuj",
},
},
},
}
userGetRequest := &pb.SendJsonRequest{
UserID: "A123",
Details: item,
}
res, err := userClient.SendJson(ctx, userGetRequest)
}
最佳答案
基于这个原型(prototype)文件。
syntax = "proto3";
package messages;
import "google/protobuf/struct.proto";
service UserService {
rpc SendJson (SendJsonRequest) returns (SendJsonResponse) {}
}
message SendJsonRequest {
string UserID = 1;
google.protobuf.Struct Details = 2;
}
message SendJsonResponse {
string Response = 1;
}
我认为使用 google.protobuf.Struct
类型是一个很好的解决方案。
大家的回答,一开始给了我很多帮助,所以我想对你们的工作表示感谢! :) 我真的很感激这两种解决方案! :)
另一方面,我想我找到了一个更好的方法来生成这些类型的 Structs
。
Anuj 的解决方案
这有点过于复杂,但它可以工作。
var item = &structpb.Struct{
Fields: map[string]*structpb.Value{
"name": &structpb.Value{
Kind: &structpb.Value_StringValue{
StringValue: "Anuj",
},
},
"age": &structpb.Value{
Kind: &structpb.Value_StringValue{
StringValue: "Anuj",
},
},
},
}
卢克的解决方案
这是一个较短的,但仍然需要比必要更多的转换。 map[string]interface{} -> bytes -> Struct
m := map[string]interface{}{
"foo":"bar",
"baz":123,
}
b, err := json.Marshal(m)
s := &structpb.Struct{}
err = protojson.Unmarshal(b, s)
我的解决方案
我的解决方案将使用来自 structpb
包的官方函数,该包有很好的文档记录且用户友好。
文档: https://pkg.go.dev/google.golang.org/protobuf/types/known/structpb
例如,此代码通过旨在执行此操作的函数创建了一个 *structpb.Struct
。
m := map[string]interface{}{
"name": "Anuj",
"age": 23,
}
details, err := structpb.NewStruct(m) // Check to rules below to avoid errors
if err != nil {
panic(err)
}
userGetRequest := &pb.SendJsonRequest{
UserID: "A123",
Details: details,
}
当我们从 map[string]interface{}
构建 Struct
时,我们应该牢记的最重要的事情之一是:
https://pkg.go.dev/google.golang.org/protobuf/types/known/structpb#NewValue
// NewValue constructs a Value from a general-purpose Go interface.
//
// ╔════════════════════════╤════════════════════════════════════════════╗
// ║ Go type │ Conversion ║
// ╠════════════════════════╪════════════════════════════════════════════╣
// ║ nil │ stored as NullValue ║
// ║ bool │ stored as BoolValue ║
// ║ int, int32, int64 │ stored as NumberValue ║
// ║ uint, uint32, uint64 │ stored as NumberValue ║
// ║ float32, float64 │ stored as NumberValue ║
// ║ string │ stored as StringValue; must be valid UTF-8 ║
// ║ []byte │ stored as StringValue; base64-encoded ║
// ║ map[string]interface{} │ stored as StructValue ║
// ║ []interface{} │ stored as ListValue ║
// ╚════════════════════════╧════════════════════════════════════════════╝
//
// When converting an int64 or uint64 to a NumberValue, numeric precision loss
// is possible since they are stored as a float64.
例如,如果您想生成一个包含 JSON 格式字符串列表的 Struct
,您应该创建以下 map[string]interface{}
m := map[string]interface{}{
"name": "Anuj",
"age": 23,
"cars": []interface{}{
"Toyota",
"Honda",
"Dodge",
}
}
抱歉发了这么长的帖子,我希望它能让你使用 proto3
和 Go
的工作更轻松! :)
关于json - "google/protobuf/struct.proto"是通过 GRPC 发送动态 JSON 的最佳方式吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52966444/