起啥名都已存在 2024-10-15 17:39 采纳率: 0%
浏览 6

protobuf生成json问题

golang使用protobuf生成接口,message生成的结构体字段,json标签中均包含omitempty,后面在进行结构体->json转换时,由于字段值为空,json中包含的字段没有该k-v。导致的问题:接口鉴权计算SHA时,由于字段确实,程序和传递过来的SHA值总是不同

  • 写回答

1条回答 默认 最新

  • 越重天 新星创作者: Java技术领域 2024-10-17 12:26
    关注

    本答案参考 多次询问 ChatGPT-3.5 后选择的最佳回答,若是满意,还请采纳,谢谢

    以下是对这个问题的分析和可能的解决方案:

    一、问题分析

    1. 关于omitempty标签
      • 在Go中,当使用protobuf生成结构体时,如果json标签中包含omitempty,这意味着在将结构体转换为json时,如果该字段的值为其零值(例如,对于字符串为空字符串,对于整数为0等),则这个字段将不会被包含在生成的json数据中。
      • 例如,假设有如下的protobuf定义:
        message User {
          string name = 1;
          int32 age = 2;
        }
        
        生成的Go结构体可能类似这样(简化):
        type User struct {
          Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
          Age  int32  `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"`
        }
        
        如果创建一个User结构体实例,其中Age = 0,在将其转换为json时,age字段可能不会出现在最终的json字符串中。
    2. 接口鉴权SHA计算问题
      • 接口鉴权计算SHA时,通常是基于一个固定的格式或者包含所有相关字段的输入来计算哈希值。由于json转换时部分字段缺失(因为omitempty),导致计算SHA的输入与预期的包含所有字段的输入不同。
      • 例如,假设接口鉴权计算SHA的逻辑是基于一个包含nameage字段的json字符串。如果age字段由于omitempty被排除,那么计算出来的SHA值就会与按照完整字段计算的预期值不同。

    二、解决方案

    1. 修改json转换逻辑(不推荐长期解决方案)
      • 在将结构体转换为json时,可以手动构建一个包含所有预期字段的临时结构体或者map,然后再进行SHA计算。
      • 例如:
        user := User{Name: "John", Age: 0}
        // 创建一个包含所有字段的临时map
        data := map[string]interface{}{
          "name": user.Name,
          "age":  user.Age,
        }
        jsonData, _ := json.Marshal(data)
        // 然后使用jsonData进行SHA计算
        
      • 但是这种方法比较繁琐,并且不太符合常规的json序列化和反序列化流程。
    2. 调整protobuf生成的json标签(推荐)
      • 如果在接口鉴权中需要所有字段都参与计算,即使字段值为零值,那么可以修改protobuf的生成规则,去掉omitempty标签。
      • protobufprotoc命令中,可以使用自定义的模板或者插件来控制生成的Go代码中的json标签。例如,如果使用protoc -go_out来生成Go代码,可以创建一个自定义的Go模板,在模板中去掉omitempty部分。不过这可能需要对protoc的插件和模板机制有一定的了解。
    3. 调整接口鉴权计算逻辑
      • 如果不能修改json标签或者结构体生成逻辑,可以调整接口鉴权计算SHA的逻辑。例如,可以在计算SHA之前,先检查哪些字段是预期的鉴权字段,然后根据结构体中的实际值(即使为零值)构建一个固定格式的输入字符串用于SHA计算。
      • 假设鉴权只关心nameage字段,代码可能如下:
        user := User{Name: "John", Age: 0}
        input := fmt.Sprintf("name=%s&age=%d", user.Name, user.Age)
        // 然后使用input进行SHA计算
        
    评论

报告相同问题?

问题事件

  • 创建了问题 10月15日