gRPC开发中写Proto 的注意事项
proto文件的注意事项
三种数据通道
一、proto注意事项
1.官方的示例
syntax = "proto3";
option go_package = "google.golang.org/grpc/examples/helloworld/helloworld";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
package helloworld;
// 定义一个服务
service Greeter {
// 服务中的一个调用
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// 请求参数
message HelloRequest {
string name = 1;
}
// 响应参数
message HelloReply {
string message = 1;
}
通过
go_package
或java_package
定义编译后的包路径请求参数命名以
xxxRequest
响应参数命名以
xxxReply
通过
java_multiple_files
声明每个message和service要单独编译成一个文件
2.标识号的分配
字段标识号是指 stringname=1
这句后面的1.
标识号不要求连续,如:
string name = 1;
string nickname = 12;
string age = 2;
而且可以使用 reserved 指令来保留字段和字段名,如:
reserved 1,2;
reserved "name","age";
标识号定义好后,一旦上线不可修改。否则可能会出现字段混乱的情况。
此外,1-15的标识号编码后占一个字节,16~2047 编码后占两个字节,一般不会再多了。
3.uint的使用
因为java中没有无符号整数,所以编译后会变成 long 和 int,那么无符号的限定就没什么作用了。
需要在业务中做校验。
4.枚举类型
proto 中 枚举类型内首个枚举项要求从0开始,考虑到 go 语言中零值是默认值,因此第一个元素一般是保留元素,不标识业务意义。
每个枚举类型内的枚举项也要求是唯一的。比如下面的会导致冲突,编译无法通过:
enum OpType{
None = 0;
}
enum BizType{
None = 0;
}
枚举项内的元素一般不允许重复,除非声明了 allow_alias
。比如:
enum Status {
option allow_alias = true;
None = 0;
Doing = 1;
Done = 1;
}
二、三种数据通道
RPC调用的过程中,一般有三种数据:
主要传输的消息体,message中定义的消息
错误的返回值
公共的参数
本篇只做简单介绍,因为每个点拿出来都足够写一篇文章了,后续会有详细介绍。
1. metadata
gRPC 是基于 http2的,在请求和返回时可以把一些数据放到 header中。
利用这种特性,gRPC构造了一种 key:value
结构的数据格式,叫 metadata。
它将header作为载体,可以在请求和响应中额外传输数据。
比如我们定义了metadata 的 appname,在gRPC请求时,会转为如下header:
2.错误返回值
gRPC官方只支持固定几种错误码,这些错误码太少了,无法完全表达具体业务错误。
然而grpc错误中的message也绝不是放置错误标识的字段,因为其不可控性太强。
还有些开发者在定义返回值时,会在定义的时候固定将错误码和消息包含在内,如:
message LoginReply{
int32 code = 1;
string msg = 2;
int64 uid = 3;
}
这也并不是推荐的做法:因为会导致重复工作太多。
Google推荐了一种,把错误详细信息编码后,放到 metadata 来返回的方式。
3.公共参数处理
很多接口也有公共参数,将公共参数放入message中不仅会带来大量重复工作,而且非常不利于后续通用字段的添加。
所以做法还是放到 metadata中。
4.小结
http请求其实就那么几个可以传输的地方:
URL中的query参数
header
POST请求中的body
gRPC将message放到了body,metdata放到了header。