官方网站 https://protobuf.dev/ https://github.com/protocolbuffers/protobuf https://grpc.io/ https://github.com/grpc/grpc
安装 https://github.com/protocolbuffers/protobuf/releases
下载对应系统的 zip 包,解压就可以得到编译后的 protoc 二进制文件。 在类 unix 系统下,可以将 include 中的 proto 文件拷贝到 ‘/usr/local/include/‘ 下,方便引用官方支持的类型。
1 2 3 4 5 6 mkdir ~/temp && cd ~/tempcurl -OL https://github.com/google/protobuf/releases/download/v3.20.3/protoc-3.20.3-linux-x86_64.zip \ && mkdir protoc3 \ && unzip protoc-3.20.3-linux-x86_64.zip -d protoc3 \ && mv protoc3/bin/* /usr/local/bin/ \ && mv protoc3/include/* /usr/local/include/
https://github.com/protocolbuffers/protobuf-go/tree/master/cmd/protoc-gen-go https://github.com/grpc/grpc-go/tree/master/cmd/protoc-gen-go-grpc https://github.com/grpc-ecosystem/grpc-gateway/tree/main/protoc-gen-grpc-gateway https://github.com/grpc-ecosystem/grpc-gateway/tree/main/protoc-gen-openapiv2
我们使用 grpc-gateway 作为 demo 演示,因此需要安装 go 语言插件以及 grpc, grpc-gateway 插件。openapiv2 用于生成 swagger 文档。
1 2 3 4 go install google.golang.org/protobuf/cmd/protoc-gen-go@latest go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@latest
xxx_out=xxx 和插件 protoc-gen-xxx 的关系 对于 protoc 插件,命名为 protoc-gen-xxx
,与 protoc 的参数 --xxx_out
所对应。 举例来说,protoc 在生成 go 语言模版代码时,使用的是插件 protoc-gen-go
来生成,所以命令就是 protoc -I=. --go_out=. demo.proto
简单使用 语法参考官网 ,Protocol Buffers 最基础的功能就是序列化和反序列化。
demo.proto 1 2 3 4 5 6 7 8 syntax = 'proto3'; option go_package='./demo';message HelloRequest { string name = 1 ; }
1 protoc -I=. --go_out=. demo.proto
main.go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package mainimport ( "fmt" "protoc-demo/demo" "google.golang.org/protobuf/proto" ) func main () { b, err := proto.Marshal(&demo.HelloRequest{ Name: "Foo" , }) if err != nil { panic (err) } fmt.Printf("125ns encoded into %d bytes of Protobuf wire format:\n% x\n" , len (b), b) var hello demo.HelloRequest if err := proto.Unmarshal(b, &hello); err != nil { panic (err) } fmt.Printf("Protobuf wire format decoded to duration %v\n" , hello.Name) }
1 2 3 4 5 6 7 mkdir temp && cd tempgo mod init protoc-demo protoc -I=. --go_out=. demo.proto go mod tidy go run main.go
使用 grpc-gateway 创建 restful api 使用 grpc-gateway 需要添加 proto 扩展 google/api/annotations.proto
。
下载 google/api/http.proto, 并放到项目的 google/api 路径下。https://github.com/googleapis/googleapis/blob/master/google/api/annotations.proto https://github.com/googleapis/googleapis/blob/master/google/api/http.proto
demo.proto 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 syntax = 'proto3'; option go_package='./demo';import "google/api/annotations.proto" ;service HelloService { rpc Hello(HelloRequest) returns (HelloResponse) { option (google.api.http) = { get: "/api/v1/hello/{name}" }; } } message HelloRequest { string name = 1 ; } message HelloResponse { string msg = 1 ; }
1 protoc -I=. --go_out=. --go-grpc_out=. --grpc-gateway_out=. demo.proto
main.go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 package mainimport ( "context" "log" "net" "net/http" "os" "os/signal" "protoc-demo/demo" "syscall" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" ) var ( rpcServerPort = ":9001" gatewayPort = ":9000" ) type server struct { demo.UnimplementedHelloServiceServer } func (s *server) Hello(ctx context.Context, req *demo.HelloRequest) (*demo.HelloResponse, error ) { log.Printf("Handle HelloService Hello() request name: %s \n" , req.Name) return &demo.HelloResponse{Msg: "Hello " + req.GetName()}, nil } func main () { go runRpcServer() go runGateway() osExitSignal := make (chan os.Signal, 1 ) signal.Notify(osExitSignal, os.Interrupt, syscall.SIGTERM) sig := <-osExitSignal log.Printf("OS initiated shutdown: %v \n" , sig) } func runRpcServer () { lis, err := net.Listen("tcp" , rpcServerPort) if err != nil { log.Fatalf("failed to listen: %v" , err) } s := grpc.NewServer() demo.RegisterHelloServiceServer(s, &server{}) log.Printf("Rpc Server Start on: %s \n" , rpcServerPort) if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v" , err) } } func runGateway () { ctx := context.Background() ctx, cancel := context.WithCancel(ctx) defer cancel() mux := runtime.NewServeMux() opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())} err := demo.RegisterHelloServiceHandlerFromEndpoint(ctx, mux, rpcServerPort, opts) if err != nil { log.Fatalf("failed to RegisterHelloServiceHandlerFromEndpoint: %v" , err) } log.Printf("gateway Server Start on: %s \n" , gatewayPort) err = http.ListenAndServe(gatewayPort, mux) if err != nil { log.Fatalf("failed to ListenAndServe: %v" , err) } }
启动之后,执行 curl http://localhost:9000/api/v1/hello/world!
可以得到 Response, 则 gateway 执行成功。
如果这篇文章对你有帮助,那么不妨?
꒰ঌ(🎀ᗜ`˰´ᗜ🌸)໒꒱