我正在使用LogNet grpc-spring-boot-starter实现gRPC API。
例如,当传递了错误的参数时,我想返回一个INVALID_ARGUMENT
错误代码。
如果我抛出自定义异常,则其结尾为io.grpc.StatusRuntimeException: UNKNOWN
。
问:是否可以定义某种异常处理机制,以便特定类型的异常始终导致正确的gRPC状态?
不幸的是,该项目中没有太多的文档。
答案 0 :(得分:2)
gRPC阻止您抛出异常以将错误传达给用户。这是因为意外泄漏您可能没有考虑发送给客户端的信息很简单。
相反,建议您将StatusException
或StatusRuntimeException
传递给streamObserver.onError(Throwable)
。如果您使用异常在自己的代码中传达此信息,则可以在代码中放入try-catch并将异常传递给onError()
。例如,这对StatusException
来说可能是合理的,因为它是一个已检查的异常。
有TransmitStatusRuntimeExceptionInterceptor会在回调过程中捕获异常,如果它是StatusRuntimeException
,请以异常状态关闭呼叫。这与您的要求非常匹配,但是默认情况下没有故意启用它。
答案 1 :(得分:0)
我刚刚发表了关于该主题Exception Handling and Error Propagation in gRPC Java的文章。
您可以使用拦截器来处理异常,例如:
public class ExceptionHandler implements ServerInterceptor {
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall, Metadata metadata,
ServerCallHandler<ReqT, RespT> serverCallHandler) {
ServerCall.Listener<ReqT> listener = serverCallHandler.startCall(serverCall, metadata);
return new ExceptionHandlingServerCallListener<>(listener, serverCall, metadata);
}
private class ExceptionHandlingServerCallListener<ReqT, RespT>
extends ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT> {
private ServerCall<ReqT, RespT> serverCall;
private Metadata metadata;
ExceptionHandlingServerCallListener(ServerCall.Listener<ReqT> listener, ServerCall<ReqT, RespT> serverCall,
Metadata metadata) {
super(listener);
this.serverCall = serverCall;
this.metadata = metadata;
}
@Override
public void onHalfClose() {
try {
super.onHalfClose();
} catch (RuntimeException ex) {
handleException(ex, serverCall, metadata);
throw ex;
}
}
@Override
public void onReady() {
try {
super.onReady();
} catch (RuntimeException ex) {
handleException(ex, serverCall, metadata);
throw ex;
}
}
private void handleException(RuntimeException exception, ServerCall<ReqT, RespT> serverCall, Metadata metadata) {
if (exception instanceof IllegalArgumentException) {
serverCall.close(Status.INVALID_ARGUMENT.withDescription(exception.getMessage()), metadata);
} else {
serverCall.close(Status.UNKNOWN, metadata);
}
}
}
}
答案 2 :(得分:0)
starter 的最新版本集成了 spring 验证支持。如果验证失败,则返回 INVALID_ARGUMENT。
披露:我是这个启动器的创建者。
答案 3 :(得分:0)
gRPC 不会传播错误。从 official documentation -
使用给定的原因创建 Status 的派生实例。但是,原因并没有从服务器传输到客户端。
如果您想将自定义信息从服务器传递到客户端,那么您有几个选择 -
google.rpc.Status
在 repeated google.protobuf.Any details
中传递错误详细信息您需要在两种情况下捕获异常,准备错误消息,并将其发送回客户端。
我写了一篇关于 error handling in gRPC 的详细博文。