【问题标题】:Spring webflux filter: How to get the reactor context after the query execution?Spring webflux过滤器:查询执行后如何获取reactor上下文?
【发布时间】:2019-10-27 16:58:15
【问题描述】:

春季启动 2.1.5 项目反应堆 3.2.9

在我的 webflux 项目中,我广泛使用反应器上下文来传递一些值。

我设置了一个过滤器并尝试记录上下文中的内容,并在错误/成功的情况下记录不同的内容。

我已查看此文档:https://projectreactor.io/docs/core/release/reference/#context

我仍然在努力(尤其是在错误方面)来获得它。

基本上,我有这个过滤器:

@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
            .doAfterSuccessOrError(new BiConsumer<Void, Throwable>() {
                @Override
                public void accept(Void aVoid, Throwable throwable) {
                    //Here i would like to be able to access to the request's context
                    System.out.println("doAfterSuccessOrError:" + (throwable==null ? "OK" : throwable.getMessage())+"log the context");
                }
            })
            .doOnEach(new Consumer<Signal<Void>>() {
                @Override
                public void accept(Signal<Void> voidSignal) {
                    //Here i have the context but i don't really know if i am in success or error
                    System.out.println("doOnEach:"+"Log OK/KO and the exception" + voidSignal.getContext());
                }
            })
            .subscriberContext(context -> context.put("somevar", "whatever"));
    }

}

我也尝试过使用 flatMap() 和 Mono.subscriberContext(),但我不确定如何正确插入过滤器(尤其是错误时)。

实现这一目标的最佳方法是什么?

【问题讨论】:

  • 有更简洁的解决方案,但我想知道你想记录什么?
  • Business stuff....查询的行数,修改后的ids....我们从调用者那里收到的客户端id...在开始时生成的某种相关id请求并传递整个流程以了解哪个日志与哪个查询相关......等等有时我们还希望在请求结束时记录所有内容,而不是在执行期间记录多次。
  • simonbasle.github.io/2018/02/… 是你如何使用 MDC 和上下文
  • 我知道这篇文章。我使用它,它运行良好。不过,这里的主要问题是如何获取处于错误状态的上下文。
  • 更准确地说,要在错误模式下获取上下文,要知道自己处于错误模式并出现异常。

标签: spring-webflux project-reactor


【解决方案1】:

我知道这可能不是最干净的解决方案,但您可以创建一个容器类来保持两个回调之间的上下文。

您可以将上下文存储在doOnEach,然后您可以将其加载回doAfterSuccessOrError

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

        @lombok.Data
        class MyContextContainer {
            private Context context;
        }

        MyContextContainer container = new MyContextContainer();

        Mono<Void> filter = webFilterChain.filter(serverWebExchange);

        return filter
            .doAfterSuccessOrError(new BiConsumer<Void, Throwable>() {
                @Override
                public void accept(Void aVoid, Throwable throwable) {
                    // load the context here
                    Context context = container.getContext();
                    // then do your stuff here
                }
            })
            .doOnEach(new Consumer<Signal<Void>>() {
                @Override
                public void accept(Signal<Void> voidSignal) {
                    // store the context here
                    container.setContext(voidSignal.getContext());
                }
            })
            .subscriberContext(context -> context.put("somevar", "whatever"));
    }

它不需要是一个类,真的。可能是AtomicReference,但你明白了。

同样,这可能只是一种解决方法。我相信一定有更好的方法来访问上下文。

【讨论】:

  • 感谢您的想法。它确实有效。不过,我希望有一天能有一个更清洁的解决方案:)。
【解决方案2】:

我不确定是否可以从 WebFilter 中访问请求反应器上下文。 WebFilter 上下文存在于另一个 Mono 链中。 但是可以将属性与请求相关联,并能够在请求生命周期内获取这些属性RequestContextHolder for Reactive Web 非常类似于 Servlet API。

控制器:

@GetMapping(path = "/v1/customers/{customerId}")
public Mono<Customer> getCustomerById(
    @PathVariable("customerId") String customerId,
    ServerWebExchange serverWebExchange)
{
  serverWebExchange.getAttributes().put("traceId", "your_trace_id");
  return customerService.findById(customerId);
}

网络过滤器:

public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
    // ...
    String traceId = exchange.getAttributeOrDefault("traceId", "default_value_goes_here");
    //...
    return chain.filter(exchange);
}

【讨论】:

  • 它确实有效。我想出了一个类似的解决方案,以便能够在此处获取错误模块中的上下文:stackoverflow.com/questions/56577196/…
  • 它可以工作...但是将 serverWebExchange 作为我的控制器的参数太具侵略性了。我不能认为这是一个好的解决方案。
猜你喜欢
  • 2018-09-09
  • 2019-07-23
  • 2022-07-22
  • 1970-01-01
  • 2021-12-02
  • 1970-01-01
  • 2017-10-14
  • 2022-12-19
  • 1970-01-01
相关资源
最近更新 更多