如何解析Protocol Buffer消息并转为JSON?Go客户端技术问询
问题场景
1. Proto文件定义
syntax = "proto3"; message getDhtParams {} message DhtContents { string dht_contents=1; } service MyApp { rpc getDhtContent(getDhtParams) returns (DhtContents) {} }
说明:这是极简版本,实际文件内容更丰富;Python服务端已生成并运行。
2. Go客户端获取代码
func fetchDht() (*pb.DhtContents, error) { // Set up a connection to the server. address := "localhost:9998" conn, err := grpc.Dial(address, grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { log.Fatalf("did not connect: %v", err) } defer conn.Close() client := pb.NewMyAppClient(conn) ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() r, err := client.GetDhtContent(ctx, &pb.GetDhtParams{}) if err != nil { return nil, errors.New("could not get dht contents") } return r, nil }
3. 响应示例
dht_contents:"{'node_ids': ['dgxydhlqoopevxv'], 'peer_addrs': [['192.168.1.154', '41457']], 'peer_meta': [{'peer_id': {'nodeID': 'dgxydhlqoopevxv', 'key': 'kdlvjdictuvgxspwkdizqryr', 'mid': 'isocvavbtzkxeigkkrubzkcx', 'public_key': 'uhapwxnfeqqmnojsaijghhic', '_address': 'xklqlebqngpkxb'}, 'ip_addrs': ['192.168.1.154', '41457'], 'services': [{'service_input': '', 'service_output': '', 'price': 0}], 'timestamp': 1661319968}]}"
注意点:
- 以
dht_contents:开头,是DhtContents消息的字段; - 字段内容使用单引号,属于非标准JSON格式。
疑问
- 如何用Protocol Buffer/gRPC的优雅方式提取
dht_contents字段双引号内的内容? - 如何将该内容转换为标准JSON?已创建对应的结构体用于反序列化。
另外,若能将*pb.DhtContents类型响应转换为[]byte,也可自行完成后续JSON转换。
解决方案
1. 提取dht_contents字段内容
*pb.DhtContents是Protobuf生成的结构体,直接访问公开字段即可拿到目标内容:
resp, err := fetchDht() if err != nil { // 处理错误逻辑 } rawContent := resp.DhtContents // 直接获取双引号内的字符串
如果需要将整个*pb.DhtContents转为[]byte,用Protobuf标准序列化方法即可:
import "google.golang.org/protobuf/proto" // ... respBytes, err := proto.Marshal(resp) if err != nil { // 处理序列化错误 }
更直接的方式是将字段值直接转成字节数组:[]byte(rawContent)。
2. 转换为标准JSON
针对单引号格式的非标准JSON,分两种场景处理:
方式一:简单替换(无嵌套单引号场景)
如果内容里的字符串值不包含单引号,全局替换单引号为双引号即可:
import "strings" standardJson := strings.ReplaceAll(rawContent, "'", "\"") // 后续可直接用json.Unmarshal反序列化到你的结构体
方式二:用兼容库解析(复杂场景)
如果内容中存在带单引号的字符串,替换会出错,推荐使用支持单引号JSON的第三方库解析:
import "github.com/json-iterator/go" var json = jsoniter.ConfigCompatibleWithStandardLibrary // 你的结构体定义示例 type DhtData struct { NodeIDs []string `json:"node_ids"` PeerAddrs [][]string `json:"peer_addrs"` PeerMeta []PeerMetaContent `json:"peer_meta"` } type PeerMetaContent struct { PeerID PeerIDInfo `json:"peer_id"` IPAddrs []string `json:"ip_addrs"` Services []Service `json:"services"` Timestamp int64 `json:"timestamp"` } // 其余结构体字段自行补充 var target DhtData err := json.Unmarshal([]byte(rawContent), &target) if err != nil { // 处理解析错误 }
内容的提问来源于stack exchange,提问作者Santosh Kumar
相关产品推荐
相关产品推荐

