Spring webflux обработчик ошибок: как получить контекст реактора запроса в обработчике ошибок? - PullRequest
3 голосов
/ 13 июня 2019

Spring boot 2.1.5 Project Reactor 3.2.9

В моем проекте webflux я широко использую контексты реактора, чтобы передать некоторые значения.

Моя цель - получить контекст внутри обработчика исключений.

Простой пример:

@Component
@Order(-2)
public class GlobalErrorWebExceptionHandler extends
    AbstractErrorWebExceptionHandler {

    public GlobalErrorWebExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties, ApplicationContext applicationContext, ServerCodecConfigurer configurer) {
        super(errorAttributes, resourceProperties, applicationContext);
        this.setMessageWriters(configurer.getWriters());
    }

    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(
      ErrorAttributes errorAttributes) {
        return RouterFunctions
            .route(RequestPredicates.all(), request -> {
                Throwable error = errorAttributes.getError(request);

                return ServerResponse.status(500).syncBody(error.getMessage()).doOnEach(serverResponseSignal -> {
                    //Here the context is empty because i guess i created a new flux
                    System.out.println("What is in my context ? " + serverResponseSignal.getContext());
                    System.out.println("What is my exception ? " + error);
                });
            });
    }

}

Я не уверен, как достичь этой цели с помощью реактора. У кого-нибудь есть идея?

1 Ответ

1 голос
/ 14 июня 2019

Я нашел способ добиться этого.Это не звучит чисто, но, похоже, работает.

В фильтре я сохраняю подписанный контекст в атрибуте запроса:

@Component
public class MdcWebFilter implements WebFilter {

    @NotNull
    @Override
    public Mono<Void> filter(@NotNull ServerWebExchange serverWebExchange,
                             WebFilterChain webFilterChain) {

        Mono<Void> filter = webFilterChain.filter(serverWebExchange);
        return filter
            .subscriberContext((context) -> {
                //This code is executed before the query

                Context contextTmp = context.put("whatever", "whichever");

                //I save the context in an attribute attribute
                serverWebExchange.getAttributes().put("context", contextTmp);

                return contextTmp;
            });
    }
}

Затем после этого можно получить его изобработчик реактивной ошибки:

@Component
@Order(-2)
public class GlobalErrorWebExceptionHandler extends
    AbstractErrorWebExceptionHandler {

    public GlobalErrorWebExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties, ApplicationContext applicationContext, ServerCodecConfigurer configurer) {
        super(errorAttributes, resourceProperties, applicationContext);
        this.setMessageWriters(configurer.getWriters());
    }

    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(
      ErrorAttributes errorAttributes) {
        return RouterFunctions
            .route(RequestPredicates.all(), request -> {
                Throwable error = errorAttributes.getError(request);

                //The context will be visible in the whole error handling flow
                return ServerResponse.status(500).syncBody(error.getMessage())
                   .subscriberContext((Context) request.attribute("context").orElse(Context.empty())));
            });
    }

}
...