【问题标题】:Spring gRPC - How intercept an exception with body infoSpring gRPC - 如何使用正文信息拦截异常
【发布时间】:2021-01-15 20:11:23
【问题描述】:

我有一个使用 spring gRPC 的项目。我创建了一个拦截器,当服务响应成功时,拦截器工作正常,但是当服务捕获异常时,拦截器不起作用。

服务:

@GrpcService
public class ClientAppImpl extends ClientAppGrpc.ClientAppImplBase {
    
    @Autowired MyService myService;

    @Override
    public void myMethod(Request request, StreamObserver<CreateDigitalCertificateResponse> responseObserver) {
        try {
            Response response = myService.doStuff(request);
            responseObserver.onNext(response);
            responseObserver.onCompleted();
        } catch(Exception ex) {
            responseObserver.onError(Status.INTERNAL.withDescription(exception.getMessage()).withCause(exception).asRuntimeException());
        }

    }
}

拦截器:

@GrpcGlobalServerInterceptor
public class GrpcServerInterceptor implements ServerInterceptor {

    public static final String REQUEST_ID_HEADER = "request-id-bin";
    public static final Metadata.Key<byte[]> REQUEST_ID_METADATA_KEY = Metadata.Key.of(REQUEST_ID_HEADER, Metadata.BINARY_BYTE_MARSHALLER);
    private static final Map<String, GrpcCall> CALLS = new HashMap<>();

    @Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {

        ForwardingServerCall<ReqT, RespT> responseServerCall = new ForwardingServerCall.SimpleForwardingServerCall<ReqT, RespT>(call) {
            @Override
            public void sendMessage(RespT response) {
                String callId = new String(headers.get(REQUEST_ID_METADATA_KEY));

                GrpcCall grpcCall = CALLS.get(callId);
                grpcCall.setResponse(response);

                GrpcCallProcessor grpcCallProcessor = new GrpcCallProcessor(grpcCall);
                grpcCallProcessor.processCall();

                super.sendMessage(response);
            }

        };

        ServerCall.Listener<ReqT> listenerWithContext = Contexts.interceptCall(Context.current(), responseServerCall, headers, next);

        return new ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT>(listenerWithContext) {

            @Override
            public void onMessage(ReqT request) {
                String callId = UUID.randomUUID().toString();

                headers.put(REQUEST_ID_METADATA_KEY, callId.getBytes());

                GrpcCall grpcCall = new GrpcCall();
                grpcCall.setCall(call);
                grpcCall.setHeaders(headers);
                grpcCall.setRequest(request);

                CALLS.put(callId, grpcCall);

                super.onMessage(request);
            }
        };
    }
}

当服务没有捕获到异常时,拦截器正常工作,并调用方法 sendMessage。但是当服务捕获异常时,不会调用 sendMessage 方法。

有什么方法可以拦截异常,并在拦截器中获取请求体?

谢谢!

【问题讨论】:

    标签: java spring grpc grpc-java


    【解决方案1】:

    如果myService.doStuff() 抛出异常,则不会发送任何消息sendMessage() 不会被调用,但close(Status, Metadata) 仍然会。

    headers 的当前用法已损坏。 Metadata 不是线程安全的,您不知道对象的当前“所有者”正在使用它做什么。 headers.get(REQUEST_ID_METADATA_KEY) 应直接在interceptCall() 内执行,然后再返回。

    尚不完全清楚onMessage() 的用途是什么,但看起来您应该在interceptCall() 中复制元数据 (new Metadata().merge(headers)。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-19
    • 2016-03-14
    • 1970-01-01
    • 2019-10-25
    • 2022-07-12
    • 2017-02-09
    • 2014-07-19
    相关资源
    最近更新 更多