protobuf 介绍,Python 和 Go 编写 rpc 服务(gRPC) (22)

先来看看 Python 的服务端:

import grpc pb2, pb2_grpc = grpc.protos_and_services("hello.proto") class Hello(pb2_grpc.HelloServicer): def SayHello(self, request, context): name = request.name if name != "神乐七奈": # 调用 context.set_code 来设置状态码,只要设置的不是 grpc.StatusCode.OK,那么客户端在调用时一律会产生异常 context.set_code(grpc.StatusCode.NOT_FOUND) # 设置异常信息 context.set_details("不存在 SayHello 方法") return pb2.HelloResponse(info={"name": "神乐七奈"}) if __name__ == \'__main__\': from concurrent.futures import ThreadPoolExecutor grpc_server = grpc.server(ThreadPoolExecutor(max_workers=4)) pb2_grpc.add_HelloServicer_to_server(Hello(), grpc_server) grpc_server.add_insecure_port("127.0.0.1:22222") grpc_server.start() grpc_server.wait_for_termination()

再来看看 Python 的客户端:

import grpc pb2, pb2_grpc = grpc.protos_and_services("hello.proto") channel = grpc.insecure_channel("127.0.0.1:22222") client = pb2_grpc.HelloStub(channel=channel) response= client.SayHello(pb2.HelloRequest(name="神乐七奈")) print(response.info) # {\'name\': \'神乐七奈\'} try: response= client.SayHello(pb2.HelloRequest(name="神乐七奈~")) except Exception as e: print(e) """ <_InactiveRpcError of RPC that terminated with: status = StatusCode.NOT_FOUND details = "不存在 SayHello 方法" debug_error_string = "{"created":"@1613751719.885000000","description":"Error ", ...}" > """ # 我们看到客户端抛出了异常,那我们如何才能拿到里面的信息呢 try: response = client.SayHello(pb2.HelloRequest(name="神乐七奈~")) except Exception as e: arg = e.args[0] print(arg.details) # 不存在 SayHello 方法 print(arg.code.name) # NOT_FOUND print(arg.code.value) # (5, \'not found\') # 虽然上面可以实现,但是我们应该使用其它的异常,grpc 为我们提供了一个 grpc.RpcError try: response = client.SayHello(pb2.HelloRequest(name="神乐七奈~")) except grpc.RpcError as e: print(e.details()) # 不存在 SayHello 方法 print(e.code().name) # NOT_FOUND print(e.code().value) # (5, \'not found\')

然后我们来看看如何在 Go 里面进行错误处理,首先用 proto 文件生成 Go 文件。

然后编写 Go 的服务端:

package main import ( "context" "fmt" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "matsuri/yoyoyo" "net" ) type Server struct { } func (s *Server) SayHello (ctx context.Context, request *yoyoyo.HelloRequest) (*yoyoyo.HelloResponse, error) { name := request.Name if name != "神乐七奈" { // 我们之前说可以通过 status 设置异常、codes 设置状态码 return nil, status.Error(codes.NotFound, "不存在此方法") } res := new(yoyoyo.HelloResponse) res.Info = map[string]string{"name": "神乐七奈"} return res, nil } func main() { server := grpc.NewServer() yoyoyo.RegisterHelloServer(server, &Server{}) listener, err := net.Listen("tcp", ":33333") if err != nil { fmt.Println(err) return } if err = server.Serve(listener); err != nil { fmt.Println(err) return } }

接下来先不编写 Go 客户端,用 Python 客户端测试一下试试:

import grpc pb2, pb2_grpc = grpc.protos_and_services("hello.proto") # 改成 Go 服务的端口 channel = grpc.insecure_channel("127.0.0.1:33333") client = pb2_grpc.HelloStub(channel=channel) response= client.SayHello(pb2.HelloRequest(name="神乐七奈")) print(response.info) # {\'name\': \'神乐七奈\'} try: response = client.SayHello(pb2.HelloRequest(name="神乐七奈~")) except grpc.RpcError as e: print(e.details()) # 不存在此方法 print(e.code().name) # NOT_FOUND print(e.code().value) # (5, \'not found\')

我们看到没有任何问题,然后编写 Go 客户端:

package main import ( "context" "fmt" "google.golang.org/grpc" "google.golang.org/grpc/status" "matsuri/yoyoyo" ) func main() { conn, err := grpc.Dial("127.0.0.1:33333", grpc.WithInsecure()) if err != nil { fmt.Println(err) return } defer func() { _ = conn.Close() }() client := yoyoyo.NewHelloClient(conn) response, err := client.SayHello(context.Background(), &yoyoyo.HelloRequest{}) if err != nil { st, ok := status.FromError(err) if !ok { fmt.Println("错误解析失败") return } // st.Message() 返回打印信息,一个字符串 // st.Code() 返回状态码,Code 类型、uint32 的别名 fmt.Println("错误信息:", st.Message()) fmt.Println("状态码:", st.Code()) } /* 错误信息: 不存在此方法 状态码: NotFound */ response, _ = client.SayHello(context.Background(), &yoyoyo.HelloRequest{Name: "神乐七奈"}) fmt.Println(response.Info) // map[name:神乐七奈] }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwfsgj.html