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

Protobuf生成Go结构体JSON反序列化字段名不匹配,如何转为驼峰?

问题描述

我有如下Protobuf定义:

message HeaderAttributes {
  int32 page_count = 1;
  int32 total_count = 2;
}

message Header {
  HeaderAttributes header_attributes = 1;
}

使用protoc生成对应的Go结构体后,结构体的JSON标签为下划线格式:

type Header struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    HeaderAttributes *HeaderAttributes `protobuf:"bytes,1,opt,name=header_attributes,json=headerAttributes,proto3" json:"header_attributes,omitempty"`
}

type HeaderAttributes struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    PageCount  int32 `protobuf:"varint,1,opt,name=page_count,json=pageCount,proto3" json:"page_count,omitempty"`
    TotalCount int32 `protobuf:"varint,2,opt,name=total_count,json=totalCount,proto3" json:"total_count,omitempty"`
}

尝试反序列化如下JSON HTTP响应时,因字段名不匹配失败:

"header": {
        "headerAttributes": {
            "pageCount": 1,
            "totalCount": 1
        }
    }

请问如何将生成的结构体字段名转换为驼峰格式?


解决方案

方法1:修改Protobuf定义指定JSON字段名

在Protobuf字段中通过json_name选项直接指定驼峰格式的字段名,重新生成Go代码后,结构体的JSON标签会自动匹配目标格式。修改后的Protobuf定义:

message HeaderAttributes {
  int32 page_count = 1 [json_name = "pageCount"];
  int32 total_count = 2 [json_name = "totalCount"];
}

message Header {
  HeaderAttributes header_attributes = 1 [json_name = "headerAttributes"];
}

方法2:通过protoc-gen-go参数自动生成驼峰JSON标签

执行protoc命令时添加json_tag参数,让生成的Go结构体自动将下划线命名的字段转换为驼峰格式的JSON标签,无需修改Protobuf定义。命令示例:

protoc --go_out=. --go_opt=paths=source_relative --go_opt=json_tag=json:. your_proto_file.proto

方法3:自定义JSON反序列化(不推荐)

如果无法重新生成代码,可以为结构体实现UnmarshalJSON方法手动处理字段映射,但这种方式维护成本较高。示例代码:

func (h *Header) UnmarshalJSON(data []byte) error {
    type Alias Header
    aux := &struct {
        HeaderAttributes *HeaderAttributes `json:"headerAttributes"`
        *Alias
    }{
        Alias: (*Alias)(h),
    }
    if err := json.Unmarshal(data, aux); err != nil {
        return err
    }
    h.HeaderAttributes = aux.HeaderAttributes
    return nil
}

func (ha *HeaderAttributes) UnmarshalJSON(data []byte) error {
    type Alias HeaderAttributes
    aux := &struct {
        PageCount  int32 `json:"pageCount"`
        TotalCount int32 `json:"totalCount"`
        *Alias
    }{
        Alias: (*Alias)(ha),
    }
    if err := json.Unmarshal(data, aux); err != nil {
        return err
    }
    ha.PageCount = aux.PageCount
    ha.TotalCount = aux.TotalCount
    return nil
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 18:43:24