Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Protobuf 扩展指南

Protobuf 扩展指南

原创
作者头像
王磊-字节跳动
修改于 2020-05-12 15:47:41
修改于 2020-05-12 15:47:41
10.3K0
举报
文章被收录于专栏:01ZOO01ZOO

本文并非 Protobuf 的基础、语法介绍,更加关注 Protobuf 的扩展用法以及实际案例基础

这部分可以参考官方文档,proto3的语法在这里只做简要的介绍和整理。

一个 基础Message 的定义如下

代码语言:txt
AI代码解释
复制
syntax = "proto3";
import  "other.proto";

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}
  1. 字段一般是以 [ "repeated" ] type fieldName "=" fieldNumber [ "[" fieldOptions "]" ] ";" 格式定义的
  2. 通过 protoc 即其插件,这个 proto 类型的文件会被生成特定语言的结构体,这种语言里面的类型和 proto 文件中的基础类型对应关系在这里,在其他类型的对应关系上,比如 enum、timestamp、duration ( timestamp, duration 为拓展类型)等,由于不同语言的实现方式不同,转换方式也有所不同,取决于 protoc 或插件的实现。
  3. protobuf (如无特别说明,下文中指 protobuf 3)的数据结构通过一个 repeated 关键字实现,同时 v3 也支持了 map 类型。
  4. protobuf 支持嵌套,不支持继承。支持 any,oneof 等特殊的结构,实际取值方式和特定语言有关。
  5. protobuf 的结构体支持转换为 json 而非二进制格式,对应关系在这里,这点值得注意,一般来说一般语言中的结构体转换 json 有自己的转换库函数,但是如果使用 protobuf 的库来转换可能转换结构有所不同,本质原因是因为 protobuf 的库转换时的标准不同。
  6. option的定义格式是 "option" optionName "=" constant ";", 比如 option java_package = "com.example.foo"; options 有内置也有自定义的。这部分和高级部分关系比较大。
    1. options并不改变整个文件声明的含义,但却能够影响特定环境下处理方式。完整的内置选项可以在 google/protobuf/descriptor.proto 找到,不同的 option 和他所在的位置对应。
    2. option 有多种类型,比如 fileOption, fieldOption, methodOption 等等
    3. 当你需要自定义一些 option,方式是使用 proto2 的 extend 语法,下面给出了一个例子
代码语言:txt
AI代码解释
复制
import "google/protobuf/descriptor.proto";
extend google.protobuf.MessageOptions {
  optional string my_option = 51234;
}
message MyMessage {
  option (my_option) = "Hello world!";
}

// Java 中获取这个 option 
value = my_proto_file_pb2.MyMessage.DESCRIPTOR.GetOptions()
  .Extensions[my_proto_file_pb2.my_option]

另一个真实的例子,来自 google 的 http 扩展,这里插件会获取 名为 google.api.http 的 option,然后转换为 http 结构

代码语言:txt
AI代码解释
复制
extend google.protobuf.MethodOptions {
  // See `HttpRule`.
  HttpRule http = 72295728;
}


// 实际使用
service Messaging {
    rpc GetMessage(GetMessageRequest) returns (Message) {
        option (google.api.http) = {
                get:"/v1/messages/{message_id}"
            };
    }
}

扩展

protobuf 描述一切

本质上,protobuf 的能力是描述 entitymethod,基本上 entity、method 外加一些约定,就可以描述所有的协议了。事实上 google 的 api 定义 基本上都可以都可以找到 protobuf 的描述

这里 protobuf 的描述作用就可以是

  1. 一个可以被复用的类型 (或者是一种 WellKnownType)。
  2. 一个 rpc 服务的输入输出类型,或者 rpc 服务的 service 以及 method。
  3. 一个描述某种协议(基于 protobuf 扩展 )的元信息结构和扩展位置的约定。
  4. 其他各种内置或扩展的 proto 文件元信息 key value。

甚至,protobuf 能够描述 protobuf 自己。protoc 以及插件的解析 proto 文件原理中最重要的是一个 descriptor 结构,而这个结构也是 protobuf 描述的,这是一个鸡生蛋还是蛋生鸡的关系,事实上,最初的 descriptor 是开发 compile 的开发者手动写的,经过一段时间,再用 protoc 生成 descriptor 文件,用于 protoc 文件 (似乎是一种循环依赖)。

http 扩展

如上所述,google api 中定义了如何将 grpc 映射成 http 的协议,理解这套协议以及实现,是理解扩展 protobuf 的一个很好的出发点。

  1. 首先定义 映射协议以及描述对应关系的 entity, 这个 entity比较简单,文件 大部分实在描述映射的协议,以便于实际实现方参考这个描述来实现。
  2. 使用 protobuf 的 extend option 的方法来扩展协议,这之后就可以使用相关的关键字来定义 google.http.rule, 比如 option (google.api.http) = {get:"/v1/messages/{message_id}}
  3. 实现插件,使用相关的 descriptor 提取 proto 中的信息,转换为 httpRule 结构体,比如 grpc-ecosystem/grpc-gateway 里面的 protoc-gen-grpc-gateway 插件就利用这种方法提取出了 httpRule 结构,然后利用这种结构来实现来 grpc 方法对应的 http handler。比如这个函数 就是提取 httpRule 结构的方法。至此就实现了 结构、协议、proto 文件、生成文件直接的对应转换。
protobuf-http-extension
protobuf-http-extension

gogo 扩展

gogo-protobuf 是 protoc 的 go 语言插件的实现,在实现特定语言代码生成的基础了,实现了多种 扩展特性,原始的定义在 这里 , 有以下几类

  1. google.protobuf.EnumOptions/EnumValueOptions:Enum 选项,如 goproto_enum_prefix 表示 enum 前缀开关
  2. google.protobuf.FileOptions:全局/文件选项,如goproto_getters_all 是全局的打开是否生成 get 函数的开关,也有对应的 MessageOptions - goproto_gette
  3. google.protobuf.MessageOptions:类型选项,同上,只是作用范围不同
  4. oogle.protobuf.FieldOptions:字段选项,比较常用的有 nullable - 表示生成指针还是结构体,stdtime 表示转换 WellKnownType timestamp 为 time.Time 等

实际实现和一般的 protoc 的插件并无不同,descriptor 结构由 protoc 解析,插件从 descriptor 进一步的解析出 proto 文件结构,以及各种扩展的选项,然后生成go 语言的文件。

以 nullable 这个选项为例,生成语言文件的时候会使用 帮助函数 判断对应 field 是否设置了 Nullable 的 Extension,如果没设置或者设置为True,则生成的结构则带指针,默认值为 nil。

参考

  1. https://colobu.com/2019/10/03/protobuf-ultimate-tutorial-in-go/
  2. https://colobu.com/2015/01/07/Protobuf-language-guide/
  3. https://blog.csdn.net/xeseo/article/details/12832577

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Protobuf 语法指南
本指南描述了怎样使用protocol buffer 语法来构造你的protocol buffer数据,包括.proto文件语法以及怎样生成.proto文件的数据访问类。
beifengtz
2019/08/26
4.2K0
Go - 如何编写 ProtoBuf 插件 (一) ?
在 proto3 中,常见的实现插件的方式是使用 自定义选项,也就是 extend 标签,其中支持的 extend Options 有:
新亮
2021/12/06
5590
ProtoBuf 生成 Go 代码去掉 JSON tag omitempty
我们经常使用 PB(ProtoBuf)作为数据的交换协议,用于数据的序列化与反序列化。对于 PB 生成的 Go strutc,将其序列化为 JSON 时,比如对于数字类型,默认值为零,将不会出现在 JSON 串中。
恋喵大鲤鱼
2022/06/02
5.9K0
ProtoBuf 生成 Go 代码去掉 JSON tag omitempty
Go - 如何编写 ProtoBuf 插件(二)?
上篇文章《Go - 如何编写 ProtoBuf 插件 (一) 》,分享了使用 proto3 的 自定义选项 可以实现插件的编写,说到基于 MethodOptions 和 ServiceOptions 选项去实现 method 和 service 自定义设置拦截器。
新亮
2021/12/20
6380
Protobuffer 官方文档学习
该文件的第一行指定您使用的是proto3语法:如果不这样做,协议缓冲区编译器将假定您正在使用proto2。 这必须是文件的第一个非空,非注释行。
solate
2019/07/19
8.2K0
基于protobuf的代码生成
前段时间我用 Python 和 Mako 模板引擎重新梳理了我们项目中的一些重复的流程。重构了所有的RPC系统。这个工作其实完成了挺久了,但是迫于懒一直拖着没写完这篇记录,就一直没发。
owent
2021/02/24
1.6K0
基于protobuf的代码生成
Go微服务(二)——Protobuf详细入门
Protobuf是Protocol Buffers的简称,它是Google公司开发的⼀种数据描述语⾔,并于2008年对外开 源。Protobuf刚开源时的定位类似于XML、JSON等数据描述语⾔,通过附带⼯具⽣成代码并实现将结 构化数据序列化的功能。但是我们更关注的是Protobuf作为接⼝规范的描述语⾔,可以作为设计安全的 跨语⾔PRC接⼝的基础⼯具。
传说之下的花儿
2023/04/16
3.7K0
Go微服务(二)——Protobuf详细入门
【gRPC】ProtoBuf 语言快速学习指南
继上篇【gRPC】 在.Net core中使用gRPC了解了gRPC的使用,gRPC基于HTTP/2和ProtoBuf,ProtoBuf就非常有必要好好了解一下了,
DDGarfield
2022/06/23
5850
grpc系列- protobuf详解
Protocol Buffers 是一种与语言、平台无关,可扩展的序列化结构化数据的方法,常用于通信协议,数据存储等等。相较于 JSON、XML,它更小、更快、更简单,因此也更受开发人员的青眯。
lpxxn
2021/01/02
2.6K0
grpc系列- protobuf详解
go-protobuf, go-grpc-gateway和代码生成
代码生成是一种常用的生产效率技术。广义上看,编译器通过高级语言生产出低级语言或者机器码,也可以理解为一种代码生成。这种技术在现代的工程实践里往往比较常见:IDE通常自带了一些常见的单元测试生成工具;根据特定的snippet可以生成比较常用的代码片段;在go语言中,由于目前缺乏对范型对支持,为了节约重复代码,通常实现了类似技术也是使用代码生成。
王磊-字节跳动
2019/07/28
3.2K0
Protobuf 语言指南(proto3)
Protocol Buffer是Google的语言中立的,平台中立的,可扩展机制的,用于序列化结构化数据 - 对比XML,但更小,更快,更简单。您可以定义数据的结构化,然后可以使用特殊生成的源代码轻松地在各种数据流中使用各种语言编写和读取结构化数据。
sanshengshui
2019/09/11
5.7K0
go-zero使用 grpc 网关快速搭建 api
seth-shi
2023/12/18
9140
protobuf 为经络,gRPC为骨架
以来,数据结构的重要性在任何软件项目中都是毋庸置疑的。但数据结构往往又是最难相处的:
tyrchen
2020/07/23
1.1K0
Protobuf生成Go代码指南
这个教程中将会描述protocol buffer编译器通过给定的 .proto会编译生成什么Go代码。教程针对的是proto3版本的protobuf。在阅读之前确保你已经阅读过Protobuf语言指南。
KevinYan
2019/10/13
5.7K0
Go语言,Protobuf 极速入门!
Protobuf 是 Protocol Buffers 的简称,是一种与语言、平台无关,可扩展的序列化结构化数据的数据描述语言,Protobuf作为接口规范的描述语言,可以作为设计安全的跨语言PRC接口的基础工具。
微客鸟窝
2021/11/12
9110
Go语言,Protobuf 极速入门!
protoBuf-python学习笔记
protobuf通过定义包含类型结构序列化信息的文件(.proto文件),来编译生成不同语言平台的高效序列化程序代码
歪歪梯
2020/08/12
1.4K0
Go每日一库之94:protobuf
protobuf 即 Protocol Buffers,是一种轻便高效的结构化数据存储格式,与语言、平台无关,可扩展可序列化。protobuf 性能和效率大幅度优于 JSON、XML 等其他的结构化数据格式。protobuf 是以二进制方式存储的,占用空间小,但也带来了可读性差的缺点。protobuf 在通信协议和数据存储等领域应用广泛。例如著名的分布式缓存工具 Memcached 的 Go 语言版本groupcache 就使用了 protobuf 作为其 RPC 数据格式。
luckpunk
2023/09/30
7170
API 网关 gRPC-Gateway V2 初探
我们都知道 gRPC 并不是万能的工具。在某些情况下,我们仍然想提供传统的 HTTP/JSON API。原因可能从保持向后兼容性到支持编程语言或 gRPC 无法很好地支持的客户端。但是仅仅为了公开 HTTP/JSON API 而编写另一个服务是一项非常耗时且乏味的任务。
我是阳明
2021/04/09
2.5K0
API 网关 gRPC-Gateway V2 初探
protocol buffer开发指南
ProtoBuf 是一套接口描述语言(IDL)和相关工具集(主要是 protoc,基于 C++ 实现),类似 Apache 的 Thrift)。用户写好 .proto 描述文件,之后使用 protoc 可以很容易编译成众多计算机语言(C++、Java、Python、C#、Golang 等)的接口代码。(摘自:ProtoBuf 与 gRPC 你需要知道的知识)
charlieroro
2020/03/24
8610
搞定Protocol Buffers (上)- 使用篇
因为工作中gRPC使用非常频繁,而gRPC的默认序列化编码采用的也是Protocol Buffers。业界也盛传其效率及其高效:
用户3904122
2022/06/29
5.1K0
搞定Protocol Buffers (上)- 使用篇
相关推荐
Protobuf 语法指南
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档