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

Go将外部JSON反序列化为protobuf Any报错解决方法

问题根因

你遇到的问题来自三个核心错误:

  • 错误使用标准库encoding/json反序列化包含google.protobuf.Any类型的Protobuf结构体。标准JSON库不遵循Protobuf的JSON序列化规范,而Any类型的JSON格式要求必须携带@type字段标记消息类型,再将内容序列化为Protobuf二进制存入Value字段。标准库JSON只会将Any当做普通结构体解析,最终得到TypeUrl和Value都为空的无效实例。
  • 手动填充TypeUrl无法解决问题:Any.Value要求存储Protobuf二进制编码内容,直接传入JSON格式数据会导致后续UnmarshalTo解码失败。
  • 泛型初始化逻辑有误:直接声明var item T在T为指针类型时会得到nil值,传入UnmarshalTo会因为接收者为nil无法写入内容报错。
  • 额外前提:如果API返回的results数组元素没有携带符合规范的@type字段(格式通常为type.googleapis.com/包名.消息名),标准Any解析逻辑无法识别消息类型,同样会报错。
修改方案

方案1:遵循Protobuf Any规范,使用官方protojson解析

如果你的API返回格式符合Protobuf JSON规范,results元素自带@type字段,按以下方式修改:

  1. 替换反序列化依赖:使用官方google.golang.org/protobuf/encoding/protojson包替代标准encoding/json,该包内置Any类型的解析逻辑,会自动读取@type字段填充TypeUrl,并将JSON内容转成Protobuf二进制存入Value字段。
  2. 修正泛型实例初始化逻辑,确保传入UnmarshalTo的是非nil的有效消息指针。

修改后的代码如下:

import (
    "google.golang.org/protobuf/encoding/protojson"
    "google.golang.org/protobuf/proto"
)

// 注意去掉泛型约束前的~,proto.Message是接口类型不需要~约束
func getData[T proto.Message](data []byte) ([]T, error) {
    var resp ArrayRespone
    // 用protojson完成反序列化
    if err := protojson.Unmarshal(data, &resp); err != nil {
        return nil, err
    }

    var items []T
    for _, result := range resp.Results {
        // 初始化非nil的对应类型实例
        var zero T
        item := proto.Clone(zero).ProtoReflect().New().Interface().(T)

        if err := result.UnmarshalTo(item); err != nil {
            return nil, err
        }
        items = append(items, item)
    }
    return items, nil
}

方案2:绕开Any类型,直接用泛型结构体解析(推荐无@type场景使用)

如果你的API返回的results是普通JSON结构,没有携带Protobuf Any要求的@type字段,完全没必要硬用google.protobuf.Any,直接定义泛型响应结构用标准JSON解析即可,代码更简单也不会有类型解析问题:

import "encoding/json"

// 自定义泛型响应结构,标签对应API返回的JSON字段名
type ArrayResponse[T any] struct {
    Count     int32  `json:"count"`
    NextUrl   string `json:"next_url"`
    RequestId string `json:"request_id"`
    Results   []T    `json:"results"`
    Status    string `json:"status"`
}

func getData[T any](data []byte) ([]T, error) {
    var resp ArrayResponse[T]
    if err := json.Unmarshal(data, &resp); err != nil {
        return nil, err
    }
    return resp.Results, nil
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 02:51:33