用于gRPC中丰富错误处理的模式

min*_*rus 20 grpc

使用gRPC向客户端发送有关错误的更多详细信息的模式是什么?

例如,假设我有一个用于注册用户的表单,用于发送消息

message RegisterUser {
  string email = 1;
  string password = 2;
}
Run Code Online (Sandbox Code Playgroud)

电子邮件必须格式正确且唯一,密码长度必须至少为8个字符.

如果我正在编写JSON API,我将使用以下正文返回400错误:

{
  "errors": [{
    "field": "email",
    "message": "Email does not have proper format."
   }, {
     "field": "password",
     "message": "Password must be at least 8 characters."
   }],
}
Run Code Online (Sandbox Code Playgroud)

并且客户端可以向用户提供好的错误消息(即通过突出显示密码字段并特别告诉用户他们输入的内容有问题).

有了gRPC有没有办法做类似的事情?似乎在大多数客户端语言中,错误会导致抛出异常,无法获取响应.

例如,我喜欢类似的东西

message ValidationError {
  string field = 1;
  string message = 2;
}

message RegisterUserResponse {
  repeated ValidationError validation_errors = 1;
  ...
}
Run Code Online (Sandbox Code Playgroud)

或类似的.

Eri*_*son 30

在响应元数据中包含其他错误详细信息.但是,仍然要确保提供有用的状态代码和消息.在这种情况下,您可以添加RegisterUserResponse到元数据.

在gRPC Java中,它看起来像:

Metadata.Key<RegisterUserResponse> REGISTER_USER_RESPONSE_KEY =
    ProtoUtils.keyForProto(RegisterUserResponse.getDefaultInstance());
...
Metadata metadata = new Metadata();
metadata.put(REGISTER_USER_RESPONSE_KEY, registerUserResponse);
responseObserver.onError(
    Status.INVALID_ARGUMENT.withDescription("Email or password malformed")
      .asRuntimeException(metadata));
Run Code Online (Sandbox Code Playgroud)

另一个选择是使用包含额外for 的google.rpc.Statusproto.每种语言都支持处理该类型.在Java中,它看起来像:Anydetails

// This is com.google.rpc.Status, not io.grpc.Status
Status status = Status.newBuilder()
    .setCode(Code.INVALID_ARGUMENT.getNumber())
    .setMessage("Email or password malformed")
    .addDetails(Any.pack(registerUserResponse))
    .build();
responseObserver.onError(StatusProto.toStatusRuntimeException(status));
Run Code Online (Sandbox Code Playgroud)

google.rpc.Status在某些语言中更清晰,因为错误详细信息可以作为一个单元传递.它还清楚地表明响应的哪些部分与错误相关.在线,它仍然使用元数据来传递附加信息.

您可能还对error_details.proto感兴趣,其中包含一些常见类型的错误.

我在CloudNativeCon期间讨论了这个主题.您可以在YouTube上查看幻灯片和关联的录制内容.

  • io.grpc.StatusProto具有实用工具方法,可用于与com.google.rpc.Status原型进行相互转换。与io.grpc.Status相比,com.google.rpc.Status的优势在于它可以包含明显与错误相关的“细节”(而不是仅仅随意地扔到Metadata中)。如果您想提供更多错误详细信息作为服务,则`com.google.rpc.Status`应该可以正常工作。 (2认同)

vin*_*ins 5

我们有 3 种不同的方式来处理 gRPC 中的错误。例如,假设 gRPC 服务器不接受大于 20 或小于 2 的值。

选项 1:使用 gRPC 状态代码。

   if(number < 2 || number > 20){
        Status status = Status.FAILED_PRECONDITION.withDescription("Not between 2 and 20");
        responseObserver.onError(status.asRuntimeException());
    }
Run Code Online (Sandbox Code Playgroud)

选项 2:元数据(我们可以通过元数据传递对象)

   if(number < 2 || number > 20){
        Metadata metadata = new Metadata();
        Metadata.Key<ErrorResponse> responseKey = ProtoUtils.keyForProto(ErrorResponse.getDefaultInstance());
        ErrorCode errorCode = number > 20 ? ErrorCode.ABOVE_20 : ErrorCode.BELOW_2;
        ErrorResponse errorResponse = ErrorResponse.newBuilder()
                .setErrorCode(errorCode)
                .setInput(number)
                .build();
        // pass the error object via metadata
        metadata.put(responseKey, errorResponse);
        responseObserver.onError(Status.FAILED_PRECONDITION.asRuntimeException(metadata));
    }
Run Code Online (Sandbox Code Playgroud)

选项 3:使用 oneof - 我们也可以使用 oneof 发送错误响应

oneof response {
    SuccessResponse success_response = 1;
    ErrorResponse error_response = 2;
  }
}
Run Code Online (Sandbox Code Playgroud)

客户端:

switch (response.getResponseCase()){
    case SUCCESS_RESPONSE:
        System.out.println("Success Response : " + response.getSuccessResponse().getResult());
        break;
    case ERROR_RESPONSE:
        System.out.println("Error Response : " + response.getErrorResponse().getErrorCode());
        break;
}
Run Code Online (Sandbox Code Playgroud)

在此处查看详细步骤 - https://www.vinsguru.com/grpc-error-handling/