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

如何解析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格式。

疑问

  1. 如何用Protocol Buffer/gRPC的优雅方式提取dht_contents字段双引号内的内容?
  2. 如何将该内容转换为标准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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 18:54:21