本文是为后面使用
go-kit
代码生成工具truss
做一个铺垫,不会太深入去研究protobuf
用法,各位看官对于 protobuf 语法简单了解后,可以进行简单配置即可正常使用truss
,如有需要,后面再深入研究protobuf
的高级用法
前提说明
- 关于 protobuf 的由来以及优势与劣势不再赘述,在网上有很多介绍,感兴趣的看官可以自行搜索。
- 本文对于 protobuf 介绍内容比较片面,仅限于基本极少,而且会针对
truss
常用内容进行简单说明。
Protobuf
范例
废话不多说,先举个例子。
syntax = "proto3"; // 指定 protobuf 版本
package main; // 定义包名
// 引入第三方定义好的结构体,当然也可以自己定义
import "github.com/metaverse/truss/deftree/googlethirdparty/annotations.proto";
import "google/protobuf/any.proto";
import "google/protobuf/struct.proto";
//定义服务
service OauthUser {
// 定义 RPC 接口
rpc AddItem (AddItemRequest) returns (DefaultResponse) {
// 使用 protobuf 的 extend option 的方法来扩展协议
option (google.api.http) = {
// 自定义选项-自定义 head 请求
custom {
kind: "HEAD"
path: "/api/v1/item"
}
// 定义 http post 方法
additional_bindings {
post: "/api/v1/item"
body : "*"
}
};
}
rpc GetItem (GetItemRequest) returns (DefaultResponse) {
// 使用 protobuf 的 extend option 的方法来扩展协议
option (google.api.http) = {
// 定义 http get 方法
additional_bindings {
post: "/api/v1/item"
body : "*"
}
};
}
rpc UpdateItem (UpdateItemRequest) returns (DefaultResponse) {
// 使用 protobuf 的 extend option 的方法来扩展协议
option (google.api.http) = {
// 自定义选项-自定义 head 请求
custom {
kind: "HEAD"
path: "/api/v1/item/{itemId}"
}
// 定义 http post 方法
additional_bindings {
post: "/api/v1/item/{itemId}"
body : "*"
}
};
}
rpc DeleteItem (DeleteItemRequest) returns (DefaultResponse) {
// 使用 protobuf 的 extend option 的方法来扩展协议
option (google.api.http) = {
// 定义 http delete 方法
additional_bindings {
delete: "/api/v1/item/{itemId}"
body : "*"
}
};
}
}
// 定义消息体
message AddItemRequest {
// 定义参数字段
// 基本格式 :数据类型 参数=数值标签;
string itemName = 1;
string itemType = 2;
}
message GetItemRequest {
string itemId = 1;
}
message UpdateItemRequest {
string itemId = 1;
string itemName = 2;
string itemType = 3;
}
message DeleteItemRequest {
string itemId = 1;
}
message DefaultResponse {
string message = 1;
int64 code = 2;
google.protobuf.Struct data = 3;
}
protobuf 关键字说明
syntax
指定 protobuf
版本关键字,目前常用:
// syntax "proto2"
syntax "proto3"
package
指定生成代码时项目包名。
import
用于引入第三方(自定义)数据结构,常用的有:
import "github.com/metaverse/truss/deftree/googlethirdparty/annotations.proto";
import "google/protobuf/any.proto";
import "google/protobuf/struct.proto";
service
服务关键字,后面跟名称,名称最好使用驼峰
结构例如:
service OauthUser {}
rpc
定义 RPC 接口关键字, 基本格式为 rpc 接口名(请求消息体) returns (返回消息体)
,需注意的是这里的 接口名、请求消息体、返回消息体需使用 驼峰
格式命名。
例如上例中的:
rpc GetItem (GetItemRequest) returns (DefaultResponse)
rpc AddItem (AddItemRequest) returns (DefaultResponse)
rpc UpdateItem (UpdateItemRequest) returns (DefaultResponse)
rpc DeleteItem (DeleteItemRequest) returns (DefaultResponse)
option
option 关键字是对 http 接口进行扩展,通过指定的协议将 grpc 映射成为 http 协议。 如:
option 内定义需要的 HTTP 接口, 通过 custom
以及 additional_bindings
实现
// 基本格式 option (协议)
// 常用协议: google.api.http、google.api.rule
option (google.api.http) = {
// 自定义选项-自定义 head 请求
custom {
kind: "HEAD"
path: "/api/v1/item/{itemId}"
}
// 定义 http post 方法
additional_bindings {
post: "/api/v1/item/{itemId}"
body : "*"
}
}
message
字段规则
- 单数形态:一个message内同名单数形态的字段不能超过一个
- repeated:前置
repeated
关键词,声明该字段为数组类型 -
proto3
不支持proto2
中的required
和optional
关键字
消息定义
一个message
类型定义描述了一个请求或响应的消息格式,可以包含多种类型字段。
例如定义一个搜索请求的消息格式AddItemRequest
,每个请求包含名称、类型。每个字段声明以分号结尾。
如上面例子:
message AddItemRequest {
string itemName = 1;
string itemType = 2;
}
所有的字段需要前置声明数据类型,上面的示例指定了两个数值类型和一个字符串类型。除了基本的标量类型还有复合类型,如枚举、map、数组、甚至其它message类型等
分配Tags
消息的定义中,每个字段都有一个唯一的数值标签。这些标签用于标识该字段在消息中的二进制格式,使用中的类型不应该随意改动。其中,[1-15]内的标识在编码时占用一个字节,包含标识和字段类型。[16-2047]之间的标识符占用2个字节。建议为频繁出现的消息元素分配[1-15]间的标签。如果考虑到以后可能或扩展频繁元素,可以预留一些。
最小的标识符可以从1开始,最大到229 - 1,或536,870,911。不可以使用[19000-19999]之间的标识符, Protobuf协议实现中预留了这些标识符。在.proto文件中使用这些预留标识号,编译时会报错。
附上主要常用数据结构对比
.proto | C++ | Java | Python | Go | Ruby | C# |
---|---|---|---|---|---|---|
double | double | double | float | float64 | Float | double |
float | float | float | float | float32 | Float | float |
int32 | int32 | int | int | int32 | Fixnum or Bignum | int |
int64 | int64 | long | ing/long[3] | int64 | Bignum | long |
uint32 | uint32 | int[1] | int/long[3] | uint32 | Fixnum or Bignum | uint |
uint64 | uint64 | long[1] | int/long[3] | uint64 | Bignum | ulong |
sint32 | int32 | int | intj | int32 | Fixnum or Bignum | int |
sint64 | int64 | long | int/long[3] | int64 | Bignum | long |
fixed32 | uint32 | int[1] | int | uint32 | Fixnum or Bignum | uint |
fixed64 | uint64 | long[1] | int/long[3] | uint64 | Bignum | ulong |
sfixed32 | int32 | int | int | int32 | Fixnum or Bignum | int |
sfixed64 | int64 | long | int/long[3] | int64 | Bignum | long |
bool | bool | boolean | boolean | bool | TrueClass/FalseClass | bool |
string | string | String | str/unicode[4] | string | String(UTF-8) | string |
bytes | string | ByteString | str | []byte | String(ASCII-8BIT) | ByteString |
到此,对于 truss 中定义基本的 protobuf 文件的说明结束,希望各位看官有所收获,不对的地方欢迎留言指正。