MST

星途 面试题库

面试题:微服务架构下gRPC错误处理的跨服务传递

当一个微服务调用链涉及多个使用gRPC通信的服务时,如何设计错误处理机制,确保错误能正确传递且下游服务的错误信息不会暴露敏感数据给上游服务?请结合代码示例说明。
30.4万 热度难度
后端开发微服务架构

知识考点

AI 面试

面试题答案

一键面试

错误处理机制设计思路

  1. 定义标准错误码和错误信息:在所有gRPC服务中统一错误码和对应的错误信息,避免敏感信息暴露。
  2. 使用gRPC内置错误类型:利用gRPC提供的标准错误类型,如 Status.Code 来表示通用错误类型。
  3. 封装错误处理逻辑:在每个服务中封装错误处理逻辑,确保错误处理的一致性。

代码示例

假设我们有两个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)
}

通过以上方式,既能正确传递错误,又能避免下游服务的敏感信息暴露给上游服务。