gRPC例外処理

最近、gRPCを使用してサービスを初めて作成しました。サーバー側では、クライアントが表示できるように、カスタム例外を直接スローしたいと思います。最初に、私はこれを試しました:

//        responseObserver.onError(new CustomException("custom exception"));
        throw new CustomException("one error occurs");

しかし、非常に恥ずかしい結果が得られました。

io.grpc.StatusRuntimeException: UNKNOWN

クライアントは、私がカスタムスローしたエラーメッセージを見ることができません。調査の結果、サーバーからスローされたカスタム例外情報を取得できる2種類のクライアントが見つかりました。

方法1:異常メッセージをステータスの説明に設定します

サーバーの実装は次のようになります。

    // 自定义异常处理
    @Override
    public void customException(EchoRequest request, StreamObserver<EchoResponse> responseObserver) {
    
    

        try {
    
    
            if (request.getMessage().equals("error")) {
    
    
                throw new CustomException("custom exception message");
            }
            EchoResponse echoResponse = EchoResponse.newBuilder().build();
            responseObserver.onNext(echoResponse);
            responseObserver.onCompleted();
        } catch (CustomException e) {
    
    
            responseObserver.onError(Status.INVALID_ARGUMENT
                  // 这里就是我们的自定义异常信息
                    .withDescription(e.getMessage())
                    .withCause(e)
                    .asRuntimeException());
        }
    }

Status.INVALID_ARGUMENT指定された例外コードを使用します。コードも問題のパラメーターです。問題の異常なパラメーターはほとんど正常です。サービス側は明確にスローする必要があります。サービスに問題がある場合は、特別な処理を行わずに直接スローします。

クライアントコール:

   try {
    
    
            EchoResponse echoResponse = stub.customException(
                    EchoRequest.newBuilder().setMessage("error").build());
            System.out.println(echoResponse.getMessage());
        } catch (StatusRuntimeException e) {
    
    
            e.printStackTrace();
            // INVALID_ARGUMENT: occurs exception
            // 这个message 会包含 INVALID_ARGUMENT, 不是我们想需要的
            System.out.println(e.getMessage());
            if (e.getStatus().getCode() == Status.Code.INVALID_ARGUMENT) {
    
    
                // 这就是我们想要的自定义异常的信息
                System.out.println(e.getStatus().getDescription());
                // 抛出 CustomException, 方便我们的 ExceptionHandler 处理
                throw new CustomException(e.getStatus().getDescription());
            } else {
    
    
                throw e;
            }
        }

方法2:MetaDataを介してより詳細なエラー情報を渡す

このようにして、protoファイルでカスタマイズされますErrorInfo

message ErrorInfo {
    
    
  // list 里可以放很多的错误信息
  repeated string message = 1;
}

ここで定義されたErrorInfoは、多くの情報を運ぶことができます。たとえば、コードフィールドを定義して、より豊富な情報を表現することができます。

サーバー実装クラス:

    private static final Metadata.Key<ErrorInfo> ERROR_INFO_TRAILER_KEY =
            ProtoUtils.keyForProto(ErrorInfo.getDefaultInstance());
    
    @Override
    public void detailErrorMessage(EchoRequest request, StreamObserver<EchoResponse> responseObserver) {
    
    
        try {
    
    
            if (request.getMessage().equals("error")) {
    
    
                throw new CustomException("custom exception message");
            }
            EchoResponse echoResponse = EchoResponse.newBuilder().build();
            responseObserver.onNext(echoResponse);
            responseObserver.onCompleted();
        } catch (CustomException e) {
    
    
            Metadata trailers = new Metadata();
            ErrorInfo.Builder builder = ErrorInfo.newBuilder()
                    .addMessage(e.getMessage());
            trailers.put(ERROR_INFO_TRAILER_KEY, builder.build());
            responseObserver.onError(Status.INVALID_ARGUMENT
                    .withCause(e)
                    .asRuntimeException(trailers));
        }
    }

次に、クライアント呼び出しを見てください。

 try {
    
    
            EchoResponse echoResponse = stub.detailErrorMessage(
                    EchoRequest.newBuilder().setMessage("error").build());
            System.out.println(echoResponse.getMessage());
        } catch (StatusRuntimeException e) {
    
    
            if (e.getStatus().getCode() == Status.Code.INVALID_ARGUMENT) {
    
    
                Metadata trailers = Status.trailersFromThrowable(e);
                if (trailers.containsKey(ERROR_INFO_TRAILER_KEY)) {
    
    
                    ErrorInfo errorInfo = trailers.get(ERROR_INFO_TRAILER_KEY);
                    if (errorInfo.getMessageList() != null && errorInfo.getMessageList().size() != 0) {
    
    
                        // 这就是我们想要的自定义异常的信息
                        System.out.println(errorInfo.getMessageList());
                    }
                }
            } else {
    
    
                throw e;
            }
        }

上記はすべてクライアント側の同期呼び出しの例外処理です。非同期呼び出しの例外処理にはいくつかの小さな違いがあります。完全なコードは次を参照できます:https//github.com/jiaobuchong/grpc-learning/tree/master/grpc-error-handling

参考:
https://github.com/grpc/grpc-java/tree/master/examples
gRPC入門
https://grpc.github.io/grpc/core/md_doc_statuscodes.html
https://stackoverflow.com/questions / 48748745 / pattern-for-rich-error-handling-in-grpc

おすすめ

転載: blog.csdn.net/jiaobuchong/article/details/104571958