golang proto3 定义并使用 interface

1,865 阅读1分钟

需求场景

日常开发中,使用kratos框架,基于此希望使用proto3来定义全部的http请求响应的结构。

  • 某个字段的类型可能是动态的,对应的JSON类型可能是number/string/boolean/null中的其中一种。
  • 某个请求响应结构体是很复杂的,希望直接响应json类型返回到前端,后端无需处理该响应结构体的内部信息。

解决方案

  • kratos 框架默认引用的官方protobuf https://github.com/protocolbuffers/protobuf
  • 引入第三方protobuf https://github.com/gogo/protobuf

实现

1. 默认protobuf

proto文件编写

# my.proto

message MyReply{
 bytes value = 1;
}

序列化

# my.go

import "encoding/json"

func NewMyReply(v interface{}) *MyReply {
   s, err := json.Marshal(v)
   if err != nil {
      return &MyReply{
         Value: []byte(""),
      }
   }
   return &MyReply{
      Value: s,
   }
}

func (x *MyReply) MarshalJSON() ([]byte, error) {
   return x.Value, nil
}

func (x *MyReply) UnmarshalJSON(v []byte) error {
   x.Value = v
   return nil
}

测试

# my_test.go

func Test_MyReply(t *testing.T) {
   j := `{
  "explorer": {
    "minBuildNumber": 0,
    "assetBundlesFetchUrl":"xxxxx"
  },
  "servers": {
    "contentWhitelist": [
      "xxxxx"
    ]
  }
}
`
   inst := &MyReply{}
   err := json.Unmarshal([]byte(j), inst)
   if err != nil {
      t.Errorf("json decode error, err=%+v", err)
      return
   }
   str, err := json.Marshal(inst)
   if err != nil {
      t.Errorf("json encode error, err=%+v", err)
      return
   }
   t.Logf("json=%s", string(str))
}

2. 第三方gogoprotobuf

proto文件编写

# mygogo.proto

message MyReply{
 bytes value = 1[(gogoproto.customtype) = "InterfaceType"]; // InterfaceType为自定义类型
}

序列化

# mygogo.go

import (
	"encoding/json"
	"errors"
)

type InterfaceType struct {
	Value interface{}
}

func (t InterfaceType) Marshal() ([]byte, error) {
	return nil, errors.New("not implement")
}
func (t *InterfaceType) MarshalTo(data []byte) (n int, err error) {
	return 0, errors.New("not implement")
}
func (t *InterfaceType) Unmarshal(data []byte) error {
	return errors.New("not implement")
}
func (t *InterfaceType) Size() int {
	return -1
}
func (t InterfaceType) MarshalJSON() ([]byte, error) {
	return json.Marshal(t.Value)
}
func (t *InterfaceType) UnmarshalJSON(data []byte) error {
	return json.Unmarshal(data, &t.Value)
}

测试同上

附:protobuf 安装文档

...