如何在gRPC服务器中添加全局异常拦截器?

2022-09-01 10:02:16

在gRPC中,如何添加一个全局异常拦截器来拦截任何异常并将有意义的信息传播到客户端?RuntimeException

例如,一个方法可以抛出消息。在服务器端,我可以写:divideArithmeticException/ by zero

@Override
public void divide(DivideRequest request, StreamObserver<DivideResponse> responseObserver) {
  int dom = request.getDenominator();
  int num = request.getNumerator();

  double result = num / dom;
  responseObserver.onNext(DivideResponse.newBuilder().setValue(result).build());
  responseObserver.onCompleted();
}

如果客户端传递分母 = 0 ,它将得到:

Exception in thread "main" io.grpc.StatusRuntimeException: UNKNOWN

服务器输出

Exception while executing runnable io.grpc.internal.ServerImpl$JumpToApplicationThreadServerStreamListener$2@62e95ade
java.lang.ArithmeticException: / by zero

客户不知道发生了什么。

如果我想将消息传递给客户端,我必须将服务器修改为:(如本问题中所述)/ by zero )

  try {
    double result = num / dom;
    responseObserver.onNext(DivideResponse.newBuilder().setValue(result).build());
    responseObserver.onCompleted();
  } catch (Exception e) {
    logger.error("onError : {}" , e.getMessage());
    responseObserver.onError(new StatusRuntimeException(Status.INTERNAL.withDescription(e.getMessage())));
  }

如果客户端发送分母 = 0,它将得到:

Exception in thread "main" io.grpc.StatusRuntimeException: INTERNAL: / by zero

好,传递给客户端。/ by zero

但问题是,在一个真正的企业环境中,会有很多s,如果我想把这些异常的消息传递给客户端,我就要尝试抓住每一种方法,这是非常繁琐的。RuntimeException

是否有任何全局拦截器可以拦截每个方法,捕获并触发错误消息并将其传播到客户端?这样我就不必在服务器代码中处理s。RuntimeExceptiononErrorRuntimeException

多谢!

注意:

<grpc.version>1.0.1</grpc.version>
com.google.protobuf:proton:3.1.0
io.grpc:protoc-gen-grpc-java:1.0.1

答案 1

下面的代码将捕获所有运行时异常,另请参阅链接 https://github.com/grpc/grpc-java/issues/1552

public class GlobalGrpcExceptionHandler implements ServerInterceptor {

   @Override
   public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call,
         Metadata requestHeaders, ServerCallHandler<ReqT, RespT> next) {
      ServerCall.Listener<ReqT> delegate = next.startCall(call, requestHeaders);
      return new SimpleForwardingServerCallListener<ReqT>(delegate) {
         @Override
         public void onHalfClose() {
            try {
               super.onHalfClose();
            } catch (Exception e) {
               call.close(Status.INTERNAL
                .withCause (e)
                .withDescription("error message"), new Metadata());
            }
         }
      };
   }
}

答案 2

TransmitStatusRuntimeExceptionInterceptor与您想要的非常相似,除了它只捕获 。您可以分叉它并使其捕获所有异常。StatusRuntimeException

若要为服务器上的所有服务安装侦听器,可以使用在 gRPC 1.5.0 中添加的 ServerBuilder.intercept()。


推荐