proto 语法
概述
Protocol buffers 是 Google 的语言中立、平台中立、可扩展的结构化数据序列化机制——像 XML,但更小、更快、更简单。您定义了一次数据的结构化方式,然后您可以使用特殊生成的源代码轻松地将结构化数据写入各种数据流并使用各种语言从中读取结构化数据。
注意
在 go-zero 框架开发中,我们使用 《Language Guide (proto3)》 版本。
快速入门
示例 1. 编写最简单的 rpc 服务
// 声明 proto 语法版本,固定值syntax = "proto3";// proto 包名package greet;// 生成 golang 代码后的包名option go_package = "example/proto/greet";// 定义请求体message SayHelloReq {}// 定义响应体message SayHelloResp {}// 定义 Greet 服务service Greet {// 定义一个 SayHello 一元 rpc 方法,请求体和响应体必填。rpc SayHello(SayHelloReq) returns (SayHelloResp);}
示例 2. 编写流式请求服务示例
// 声明 proto 语法版本,固定值syntax = "proto3";// proto 包名package greet;// 生成 golang 代码后的包名option go_package = "example/proto/greet";// 定义结构体message SayHelloReq {}message SayHelloResp {}message SendMessageReq{string message = 1;}message SendMessageResp{int32 status = 1;}message GetMessageReq{int32 id = 1;}message GetMessageResp{string message = 1;}// 定义 Greet 服务service Greet {// 定义客户端流式 rpcrpc SendMessage(stream SendMessageReq) returns (SendMessageResp);// 定义服务端流式 rpcrpc GetMessage(GetMessageReq) returns (stream GetMessageResp);// 定义双向流式 rpcrpc PushMessage(stream SendMessageReq) returns (stream GetMessageResp);}
示例 3. 编写 rpc 分组示例
rpc 分组主要通过 service 名称来区分。
// 声明 proto 语法版本,固定值syntax = "proto3";// proto 包名package greet;// 生成 golang 代码后的包名option go_package = "example/proto/greet";// 定义结构体message SendMessageReq{string message = 1;}message SendMessageResp{int32 status = 1;}message GetMessageReq{int32 id = 1;}message GetMessageResp{string message = 1;}// 定义 Greet 服务service Greet {// 定义客户端流式 rpcrpc SendMessage(stream SendMessageReq) returns (SendMessageResp);// 定义服务端流式 rpcrpc GetMessage(GetMessageReq) returns (stream GetMessageResp);// 定义双向流式 rpcrpc PushMessage(stream SendMessageReq) returns (stream GetMessageResp);}// 定义 Greet 服务service Greet {rpc SayHello(SayHelloReq) returns (SayHelloResp);}// 定义 Message 服务service Message {// 定义客户端流式 rpcrpc SendMessage(stream SendMessageReq) returns (SendMessageResp);// 定义服务端流式 rpcrpc GetMessage(GetMessageReq) returns (stream GetMessageResp);// 定义双向流式 rpcrpc PushMessage(stream SendMessageReq) returns (stream GetMessageResp);}
示例 4. message 示例
// 声明 proto 语法版本,固定值syntax = "proto3";// proto 包名package greet;// 生成 golang 代码后的包名option go_package = "example/proto/greet";// 定义枚举enum Status{UNSPECIFIED = 0;SUCCESS = 1;FAILED = 2;}// 定义结构体message Base{int32 code = 1;string msg = 2;}message SendMessageReq{string message = 1;}message SendMessage{// 使用枚举Status status = 1;// 数组repeated string array = 2;// mapmap<string,int32> map = 3;// 布尔类型bool boolean = 4;// 序列号保留reserved 5;}message SendMessageResp{Base base = 1;SendMessage data = 2;}// 定义 Greet 服务service Greet {// 定义客户端流式 rpcrpc SendMessage(stream SendMessageReq) returns (SendMessageResp);}
示例 5. proto 文件引入
假设我们有如下环境:
- 工作路径:
/usr/local/workspace - base.proto 路径及内容:
/usr/local/workspace/base/base.proto
syntax = "proto3";// proto 包名package base;// 生成 golang 代码后的包名option go_package = "example/proto/base";message Base{int32 code = 1;string msg = 2;}
现在需要新建 /usr/local/workspace/greet/greet.proto 文件,且需要引用 /usr/local/workspace/base/base.proto 文件中的 Base 结构体,我们来看一下简单的引用示例:
// 声明 proto 语法版本,固定值syntax = "proto3";// proto 包名package greet;// 生成 golang 代码后的包名option go_package = "example/proto/greet";import "base/base.proto";enum Status{UNSPECIFIED = 0;SUCCESS = 1;FAILED = 2;}message SendMessageReq{string message = 1;}message SendMessage{// 使用枚举Status status = 1;// 数组repeated string array = 2;// mapmap<string,int32> map = 3;// 布尔类型bool boolean = 4;// 序列号保留reserved 5;}message SendMessageResp{base.Base base = 1;SendMessage data = 2;}// 定义 Greet 服务service Greet {// 定义客户端流式 rpcrpc SendMessage(stream SendMessageReq) returns (SendMessageResp);}
温馨提示
goctl 根据 proto 生成 gRPC 代码时:
- service 中的 Message(入参&出参) 必须要在 main proto 文件中,不支持引入的文件
- 引入的 Message 只能嵌套在 main proto 中的 Message 中使用
- goctl 生成 gRPC 代码时,不会生成被引入的 proto 文件的 Go 代码,需要自行预先生成