go json的omitempty标签导致protocbuf忽略默认值属性的问题

1. json序列化会丢失默认值字段

  Go的json有一个omitempty标签,意思是如果字段为空值,定义为false、0、零指针、nil接口值以及任何空数组、切片、映射或字符串,则该字段在json序列化时省略。
例如下面一段代码:

package main

import (
    "encoding/json"
    "log"
)

type Asdqwe struct {
    A int32    `json:"a,omitempty"`
    B bool     `json:"b,omitempty"`
    C [0]int32 `json:"c,omitempty"`
    D []int32  `json:"d,omitempty"`
}

func main() {
    testStruct := Asdqwe{A: 1}
    log.Printf("%v\n", testStruct)
    res, err := json.Marshal(testStruct)
    if err != nil {
        log.Fatal(err)
    }
    log.Println(string(res))
    testStruct2 := Asdqwe{}
    err = json.Unmarshal(res, &testStruct2)
    log.Printf("%v", testStruct2)
}

输出:

2020/07/13 14:36:18 {1 false [] []}
2020/07/13 14:36:18 {"a":1}
2020/07/13 14:36:18 {1 false [] []}

  可以看到,json序列化之后,除了赋值的A,其他B、C、D都没有了。但是,使用json反序列化后,重新赋予了默认值。所以这里问题不大。

2. grpc使用Protobuf时关于json这个特性的处理

  gRPC使用Protobuf,在自动生成的代码中,可以看到所有字段都加上了omitempty标签。Protobuf 2版本还可以使用required关键字,但是Protobuf 3取消了这个关键字,而我们使用gRPC基本都是使用Protobuf 3。
  大佬解释了这么设计的原因:https://stackoverflow.com/questions/31801257/why-required-and-optional-is-removed-in-protocol-buffers-3
  你如果一定要让零值存在于json序列化后的字符串中,这里有一些解决办法:https://zhuanlan.zhihu.com/p/46603988
  一个使用开源库来增加protoc特性的方法:https://studygolang.com/articles/28563?fr=sidebar
  我不喜欢这些方法。其实就像上面代码里体现的,go反序列化时能自动填充默认值/零值,所以只在grpc中传递数据时,接收方仍能正常接收到零值。如果是异构工程,其他语言不了解,java的json库对于基本数据类型也是取默认值的。

3. 一个实际使用中遇到的问题

  为了与前端交互,使用了grpc-gateway,不了解grpc-gateway的可以去看这里。前端使用js解析json时,不存在的属性不能自动赋予默认值,而是得到undefined,这就要求必须传值给前端。
  这么明显且重要的问题当然是已经被解决了的,使用grpc-gateway时,由:

gwmux := runtime.NewServeMux()

  修改为

gwmux := runtime.NewServeMux(runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{OrigName: true, EmitDefaults: true}))

  具体原因可以参考这里
  这里主要强调一点,grpc-gateway的工作原理简单而言就是:

    1. 提供对外的RESTFUL API
    1. 收到请求之后,把结果编译成proto.Message
    1. 转发请求给GPRC
    1. 收到proto.Message之后,编译成json,返回给调用者

  可以看到,grpc-gateway填充默认值,和gRPC填充默认值是不相关的。即使我们参考了常用解决方案,即使用sed命令替换掉protoc生成的代码中的omitempty标签,也只是gRPC传输时加上了默认值,grpc-gateway还是忽略默认值的。所以上面创建gwmux时的修改必不可少。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350