Protobuf Trouble Shotting
以下内容基于下面的Protoc版本。
protoc-gen-go@v1.34.1
(最新版本protoc-gen-go@v1.59.0)。protoc-gen-go-grpc@v1.2.0
(最新版本protoc-gen-go-grpc@v1.5.3)。protoc@3.20.3
(最新版本Protocol Buffers@v3.20.3)。
源码生成问题
有如下.proto
文件。
syntax = "proto3";
message HelloRequest {
string name = 1; // 1 是编号,而不是值
int32 age = 2;
}
// 运行命令
// protoc -I . helloworld.proto --go_out=plugins=grpc:.
// 上面这行命令的意思是:将当前目录下的helloworld.proto文件编译成go代码,并且将生成的代码放到当前目录下
// 但实际上,在新版本的protobuf中,这行命令是错误的
// protoc --go_out=plugins=grpc:. helloworld.proto
第一次执行protoc命令
> protoc -I . helloworld.proto --go_out=plugins=grpc:.
protoc-gen-go: program not found or is not executable
Please specify a program using absolute path or make sure the program is available in your PATH system variable
--go_out: protoc-gen-go: Plugin failed with status code 1.
再次执行go get
引入依赖。
> go get github.com/golang/protobuf/protoc-gen-go
go: module github.com/golang/protobuf is deprecated: Use the "google.golang.org/protobuf" module instead.
按照提示将命令替换成。
> go get google.golang.org/protobuf/protoc-gen-go
go: module google.golang.org/protobuf@upgrade found (v1.34.1), but does not contain package google.golang.org/protobuf/protoc-gen-go
搜索问题--go_out: protoc-gen-go: Plugin failed with status code 1.
,发现需要这样执行。
> go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.34.1
> go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
# 或者这样执行
> go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
> go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@vlatest
具体可以参考grpc官方文档。
此时在/Users/xxxx/go
目录下多出了一个bin
目录,里面有两个可执行文件:protoc-gen-go
和protoc-gen-go-grpc
,将它们放入到环境变量。
> vim /etc/profile
export GOPATH=/Users/xxxx/go
export PATH=$PATH:$GOPATH/bin
> soruce /etc/profile
# 验证版本号
> protoc-gen-go --version
protoc-gen-go v1.34.1
> protoc-gen-go-grpc --version
protoc-gen-go-grpc 1.2.0
第二次执行protoc命令
> protoc -I . helloworld.proto --go_out=plugins=grpc:.
protoc-gen-go: unable to determine Go import path for "helloworld.proto"
Please specify either:
• a "go_package" option in the .proto source file, or
• a "M" argument on the command line.
See https://protobuf.dev/reference/go/go-generated#package for more information.
--go_out: protoc-gen-go: Plugin failed with status code 1.
通过搜索引擎查找protoc-gen-go: unable to determine Go import path for "helloworld.proto"
产生的原因。
修改.proto
文件内容如下。
syntax = "proto3";
option go_package="./;helloworld";
package helloworld;
message HelloRequest {
string name = 1; // 1 是编号,而不是值
int32 age = 2;
}
// 运行命令
// protoc -I . helloworld.proto --go_out=plugins=grpc:.
// 上面这行命令的意思是:将当前目录下的helloworld.proto文件编译成go代码,并且将生成的代码放到当前目录下
// protoc --go_out=plugins=grpc:. helloworld.proto
第三次执行protoc命令
> protoc --go_out=plugins=grpc:. helloworld.proto
--go_out: protoc-gen-go: plugins are not supported; use 'protoc --go-grpc_out=...' to generate gRPC
See https://grpc.io/docs/languages/go/quickstart/#regenerate-grpc-code for more information.
第四次执行protoc命令
按照提示去掉了plugins
。
> protoc --go_out=grpc:. helloworld.proto
protoc-gen-go: no such flag -grpc
--go_out: protoc-gen-go: Plugin failed with status code 1.
第五次执行protoc命令
按照提示和官方的示例,最终改为如下方式。
> protoc --go_out=. --go-grpc_out=. helloworld.proto
成功!——同时生成了helloworld.pb.go
和helloworld_grpc.pb.go
这两个go
源代码文件。
最终将.proto
文件修改为如下内容。
syntax = "proto3";
option go_package="./;helloworld";
// grpc通过protobuf定义通信接口
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1; // 1 是编号,而不是值
int32 age = 2;
}
message HelloReply {
string reply = 1;
}
// 运行命令:
// protoc --go_out=. --go-grpc_out=. helloworld.proto
// 或者
// protoc -I . helloworld.proto --go_out=. --go-grpc_out=.
// 上面命令的意思是:
// 将当前目录下的helloworld.proto文件编译成go和grpc源码,并且将生成的源码放到当前目录下

.proto文件同步问题
message HelloRequest {
string name = 1;
int32 age = 2;
repeated string tags = 3;
}
HelloRequest
中的属性name
、age
和tags
已经被标好了顺序,就像方法中的参数顺序一样。
func getUserInfo(username, password string) {
// 业务逻辑
......
}
getUserInfo()
方法中username
和password
的顺序如果搞反了,那么业务逻辑的执行也会出错。
同理,当开发多个不同的微服务时,在不同团队之间传递.proto
文件,就有可能会出现命名搞错,编号顺序(也就是传参顺序)搞错的情况。
甚至当.proto
源文件已经被修改了,却忘了生成新的Go源码。
感谢支持
更多内容,请移步《超级个体》。