I. Environment configuration
-
1. Download the installation package of the corresponding version
-
2. Run the go env command to check your go path address and create a bin folder under the go path directory
-
3, unzip the downloads from the first point and copy the protoc under bin to the bin folder under go path
-
4. Check whether the installation is successful
# check version protoc --version # Check common commands protoc Copy the code
Currently, only these languages are supported
-
5. Configure to support go language and depend on package address
go get -u github.com/golang/protobuf/proto go get -u github.com/golang/protobuf/protoc-gen-go Copy the code
Second, the testprobuf
turngo
code
-
1. Write simple Proto files
// helloWorld.proto // Version, just stick to 3 syntax = "proto3"; // Convert to the package name of go, preceding. Output in the current directory option go_package = ".; profile"; message HelloWorld { string name = 1; int64 age = 2; double fee = 3; bool isLogin = 4; } Copy the code
-
2. Run commands to convert the proto file to the go file
#Protoc -i =.[current directory] --go_out=plugins= GRPC :.[current directory] File name protoc -I=. --go_out=plugins=grpc:. helloWorld.proto Copy the code
Three, test,
-
1. Direct output
package main import ( "fmt" "go_demo/01.protobuf/proto" ) func main(a) { hello := proto.HelloWorld{ Name: "Zhang", Age: 14, Fee: 20.9, IsLogin: false, } fmt.Println(&hello) } Copy the code
Other data types
-
1. Compound data types, in fact, are nested data
.message Location { double latitude = 1; double longitude = 2; } message HelloWorld { string name = 1; // Note that this location has nothing to do with the position, only the number behind it Location location = 5; int64 age = 2; double fee = 3; bool isLogin = 4; } Copy the code
-
2. List data types
message Location { double latitude = 1; double longitude = 2; } message HelloWorld { string name = 1; Location location = 5; int64 age = 2; double fee = 3; bool isLogin = 4; repeated Location locationList = 6; } Copy the code
-
3. Enumeration types
// Define an enumeration type enum HelloStatus { NO_PAY = 0; PAY = 1; } message HelloWorld { string name = 1; Location location = 5; int64 age = 2; double fee = 3; bool isLogin = 4; repeated Location locationList = 6; HelloStatus status = 7; } Copy the code
-
4, import another file
A similar type is used in multiple proto files. You don’t need to define a type in each proto file. You just need to define a common type and import it in other files
// base.proto syntax = "proto3"; message Empty {} Copy the code
syntax = "proto3"; import "base.proto"; option go_package=".; proto"; service Hello { rpc SayHello(Empty) returns (Empty); } Copy the code
-
5. Introduce built-in packages
syntax = "proto3"; import "google/protobuf/empty.proto"; option go_package=".; proto"; service Hello { rpc SayHello(google.protobuf.Empty) returns (google.protobuf.Empty); } Copy the code
-
6. About other built-in
-
7. Map type
message HelloWorld {... map<string.string> mp = 8; } Copy the code
-
8. Built-in time types
syntax = "proto3"; import "google/protobuf/timestamp.proto"; message HelloWorld {... google.protobuf.Timestamp addTime =9; } Copy the code
-
9. Assignment
func main(a) { var hello = proto.HelloWorld{ Name: "Zhang", Age: 14, Fee: 20.9, IsLogin: false, Location: &proto.Location{ Latitude: 30, Longitude: 100, }, LocationList: []*proto.Location{ { Latitude: 100, Longitude: 10, }, }, Status: profile.HelloStatus_NO_PAY, } fmt.Println(&hello) } Copy the code
-
10. Assignment of time
import ( "google.golang.org/protobuf/types/known/timestamppb" "time" ) var hello = profile.HelloWorld{ ... AddTime: timestamppb.New(time.Now()), } Copy the code
5. Other outputs
-
1. Use proto.Marshal to output the binary
var hell1 profile.HelloWord err = proto.Unmarshal(b, &hell1) fmt.Println(&hello) Copy the code
-
2. Output JSON
var hell1 profile.HelloWord b, err = json.Marshal(&hell1) fmt.Printf("%s\n", b) Copy the code
Realize data interaction between client and server
-
1. Define a proto file
// Version, just stick to 3 syntax = "proto3"; // Convert to the package name of go, preceding. Output in the current directory option go_package = ".; profile"; message Location { double latitude = 1; double longitude = 2; } message HelloWorld { string name = 1; Location location = 5; int64 age = 2; double fee = 3; bool isLogin = 4; repeated Location locationList = 6; } message GetHelloRequest { string id = 1; } message GetHelloResponse { string id = 1; HelloWorld helloWorld = 2; } // The service must be defined service HelloService { rpc GetHello(GetHelloRequest) returns (GetHelloResponse); } Copy the code
-
2. Run the command to generate the go file and view the service you define
func (c *helloServiceClient) GetHello(ctx context.Context, in *GetHelloRequest, opts ... grpc.CallOption) (*GetHelloResponse, error) { out := new(GetHelloResponse) err := c.cc.Invoke(ctx, "/HelloService/GetHello", in, out, opts...) iferr ! =nil { return nil, err } return out, nil } Copy the code
-
3. Define server-side methods
type Service struct{}func (*Service) GetHello(ctx context.Context, req *profile.GetHelloRequest) (*profile.GetHelloResponse, error) { return &profile.GetHelloResponse{ Id: req.Id, HelloWorld: &profile.HelloWorld{ Name: "Zhang", Age: 20, Fee: 100, IsLogin: true, Location: &profile.Location{ Longitude: 100, Latitude: 10, }, LocationList: []*profile.Location{ { Longitude: 10, Latitude: 100,},},},},nil } Copy the code
-
4. Start the server-side method
func main(a) { listen, err := net.Listen("tcp".": 9000") iferr ! =nil { log.Fatalf("Server startup failure :%v", err) } // Start the service service :=grpc.NewServer() // Service is custom from above profile.RegisterHelloServiceServer(service, &Service{}) log.Fatal(service.Serve(listen)) } Copy the code
-
5. Start the client
package main import ( "context" "fmt" "go_demo/01.protobuf/profile" "google.golang.org/grpc" "log" ) func main(a) { conn, err := grpc.Dial("localhost:9000", grpc.WithInsecure()) iferr ! =nil { log.Fatalf("Error connecting server: %v", err) } client := profile.NewHelloServiceClient(conn) response, err := client.GetHello(context.Background(), &profile.GetHelloRequest{ Id: "1001",})iferr ! =nil { log.Fatalf("Connection service error :%v", err) } fmt.Println(response) } Copy the code
Seven,protobuf
converthttp
request
-
1. Transform the proTO file before
syntax = "proto3"; // Add this package collect; option go_package = ".; profile"; Copy the code
-
2. Create a YAML file in the same proto directory
# the helloWorld. Yaml files type: google.api.Service config_version: 3 http: rules: - selector: collect.HelloService.GetHello get: /hello/{id} Copy the code
-
3. Install dependency packages
go get -u github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway Copy the code
-
4. Modify the command
#It's the same order as before protoc -I=. --go_out=plugins=grpc,paths=source_relative:. helloWorld.proto #A helloWorld.pb.gw.go file is generated protoc -I=. --grpc-gateway_out=paths=source_relative,grpc_api_configuration=helloWorld.yaml:. helloWorld.proto Copy the code
-
5. Since there are too many commands to remember, create a gen.sh file in the directory, put the two commands in it, and execute them when necessary
sh ./gen.sh Copy the code
-
6. The service layer of GRPC is the same as above
-
7. Define the HTTP client
package main import ( "context" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "go_demo/01.protobuf/profile" "google.golang.org/grpc" "log" "net/http" ) func main(a) { c := context.Background() c, cancel := context.WithCancel(c) defer cancel() mux := runtime.NewServeMux() err := profile.RegisterHelloServiceHandlerFromEndpoint( c, mux, "localhost:9000".// GRPC server address []grpc.DialOption{grpc.WithInsecure()}, ) iferr ! =nil { log.Fatalf("Error connecting GRPC: %v", err) } err = http.ListenAndServe(": 8080", mux) iferr ! =nil { log.Fatalf("Listening error: %v", err) } } Copy the code
-
8, directly enter http://localhost:8080/hello/123 in your browser
Processing the data structure of the back end back to the front end
There are two problems
- 1. We originally defined the age field as an integer and returned the character type to the front end
- We should return an enumerated value, not a string
The solution
-
1. Change the datatype of the age field from INT64 to int32
-
2. The state enumeration type is modified via the HTTP client
.var mux = runtime.NewServeMux( runtime.WithMarshalerOption( runtime.MIMEWildcard, &runtime.JSONPb{ MarshalOptions: protojson.MarshalOptions{ UseEnumNumbers: true.// Enumeration field values use numbers UseProtoNames: true, }, UnmarshalOptions: protojson.UnmarshalOptions{ DiscardUnknown: true.// Ignore the nonexistent poroto field sent by client},},),)...Copy the code