Spring Boot gRPC: как вернуть код ошибки при возникновении бизнес-ошибки? - PullRequest
0 голосов
/ 05 июля 2019

Я реализую API gRPC, используя LogNet grpc-spring-boot-starter .

Я хочу вернуть, например, код ошибки INVALID_ARGUMENT, если передан неверный аргумент.

Если я выбрасываю пользовательское исключение, оно заканчивается io.grpc.StatusRuntimeException: UNKNOWN.

Q: Можно ли определить какой-то механизм обработки исключений, чтобы исключения определенного типа всегда приводили к правильным состояниям gRPC?

К сожалению, в проекте не так много документации.

Ответы [ 2 ]

2 голосов
/ 09 июля 2019

gRPC не рекомендует выдавать исключение, чтобы сообщить об этой ошибке пользователю. Это связано с тем, что случайная утечка информации, которую вы, возможно, не рассматривали как отправку клиенту, тривиальна.

Вместо этого вам предлагается передать StatusException или StatusRuntimeException на streamObserver.onError(Throwable). Если вы используете исключения для передачи этой информации в своем собственном коде, вы можете сделать попытку в своем коде и передать исключение onError(). Например, это может быть справедливо для StatusException, поскольку это проверенное исключение.

Существует TransmitStatusRuntimeExceptionInterceptor , который будет перехватывать исключения во время обратных вызовов, и если это StatusRuntimeException, закройте вызов со статусом исключения. Это близко соответствует тому, что вы просите, но по умолчанию оно не включено по умолчанию.

0 голосов
/ 10 июля 2019

Я только что опубликовал статью на эту тему Обработка исключений и распространение ошибок в 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);
            }
        }
    }
}
...