面试题答案
一键面试错误处理机制设计思路
- 定义标准错误码和错误信息:在所有gRPC服务中统一错误码和对应的错误信息,避免敏感信息暴露。
- 使用gRPC内置错误类型:利用gRPC提供的标准错误类型,如
Status.Code
来表示通用错误类型。 - 封装错误处理逻辑:在每个服务中封装错误处理逻辑,确保错误处理的一致性。
代码示例
假设我们有两个gRPC服务,ServiceA
调用 ServiceB
。
定义proto文件
syntax = "proto3";
package example;
service ServiceB {
rpc MethodB(RequestB) returns (ResponseB);
}
message RequestB {
string data = 1;
}
message ResponseB {
string result = 1;
}
// 定义错误码
enum ErrorCode {
UNKNOWN_ERROR = 0;
INVALID_INPUT = 1;
// 其他错误码...
}
// 定义错误响应
message ErrorResponse {
ErrorCode error_code = 1;
string error_message = 2;
}
ServiceB实现
package main
import (
"context"
"fmt"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
pb "github.com/yourpath/proto"
)
type ServiceB struct{}
func (s *ServiceB) MethodB(ctx context.Context, req *pb.RequestB) (*pb.ResponseB, error) {
if req.Data == "" {
// 返回封装的错误,避免暴露敏感信息
errorResp := &pb.ErrorResponse{
ErrorCode: pb.ErrorCode_INVALID_INPUT,
ErrorMessage: "输入不能为空",
}
return nil, status.Error(codes.InvalidArgument, errorResp.ErrorMessage)
}
result := fmt.Sprintf("处理结果: %s", req.Data)
return &pb.ResponseB{Result: result}, nil
}
ServiceA调用ServiceB
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
pb "github.com/yourpath/proto"
)
func main() {
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
if err != nil {
fmt.Printf("连接失败: %v", err)
return
}
defer conn.Close()
client := pb.NewServiceBClient(conn)
req := &pb.RequestB{Data: ""}
resp, err := client.MethodB(context.Background(), req)
if err != nil {
st, ok := status.FromError(err)
if ok {
fmt.Printf("错误码: %v, 错误信息: %v\n", st.Code(), st.Message())
} else {
fmt.Printf("未知错误: %v\n", err)
}
return
}
fmt.Printf("响应结果: %v\n", resp.Result)
}
通过以上方式,既能正确传递错误,又能避免下游服务的敏感信息暴露给上游服务。