如果我立即返回ServerResponse,则ServerRequest.bodyToMono()方法返回的Mono将不会提取主体

时间:2019-09-02 16:32:09

标签: spring spring-webflux project-reactor

我在弹簧纸幅通​​量中使用纸幅反应性。我已经为POST请求实现了Handler函数。我希望服务器立即返回。因此,我实现了以下处理程序-:

public class Sample implements HandlerFunction<ServerResponse>{

public Mono<ServerResponse> handle(ServerRequest request) {

Mono bodyMono = request.bodyToMono(String.class);

bodyMono.map(str -> {
  System.out.println("body got is " + str);
  return str;
}).subscribe();

return ServerResponse.status(HttpStatus.CREATED).build();
    }
}

但是map函数内部的print语句没有被调用。这意味着身体没有被抽出。 如果我没有立即返回响应并使用

return bodyMono.then(ServerResponse.status(HttpStatus.CREATED).build())

然后调用map函数。

那么,如何在后台对请求正文进行处理? 请帮忙。

编辑

我尝试使用flux.share(),如下所示:

Flux<String> bodyFlux = request.bodyToMono(String.class).flux().share();
Flux<String> processFlux = bodyFlux.map(str -> {
      System.out.println("body got is");
      try{
        Thread.sleep(1000);
      }catch (Exception ex){

      }
      return str;
    });

    processFlux.subscribeOn(Schedulers.elastic()).subscribe();

    return bodyFlux.then(ServerResponse.status(HttpStatus.CREATED).build());

在上面的代码中,有时会调用map函数,有时不会。

2 个答案:

答案 0 :(得分:0)

正如您所发现的,您不能随意subscribe() bodyToMono()返回的Mono,因为在这种情况下,主体根本不会传递给Mono进行处理。 (您可以通过在该single()中放置一个Mono调用来进行验证,因为不会发出任何元素,它将引发异常。)

  

那么,如何在后台对我的请求正文进行处理?

如果您真的仍然想只是使用反应器在后台执行较长的任务,而立即返回,则可以执行以下操作:

return request.bodyToMono(String.class).doOnNext(str -> {
    Mono.just(str).publishOn(Schedulers.elastic()).subscribe(s -> {
        System.out.println("proc start!");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("proc end!");
    });
}).then(ServerResponse.status(HttpStatus.CREATED).build());

此方法立即将发出的元素发布到新的Mono,并设置为在弹性调度程序上发布,然后在后台进行预订。但是,这很丑陋,也不是反应堆的设计目标。您可能在这里误解了反应堆/反应式编程背后的想法:

  • 它的写意不是“返回快速结果,然后在后台执行操作”,这通常是工作队列的目的,通常使用RabbitMQ或Kafka之类的东西来实现。取而代之的是,它的“存在理由”是非阻塞性的,因此一个线程永远不会被空闲地阻塞,等待其他事情完成。
  • map()方法不是为副作用而设计的,而是旨在将每个对象转换为另一个对象的。对于副作用,您需要doOnNext()代替;
  • 默认情况下,Reactor使用单个线程,因此您在map()方法中的“其他处理”仍会阻塞该线程。

如果您的应用程序不仅仅用于快速演示目的,并且/或者您需要大量使用此模式,那么我将认真考虑设置适当的工作队列。

答案 1 :(得分:0)

这不可能。

Web服务器(包括Reactor Netty,Tomcat等)在完成请求处理后会清理并回收资源。这意味着在完成控制器处理程序后,将回收或关闭HTTP资源,请求本身,可重用缓冲区等。此时,您无法再从请求正文中进行读取。

在您的情况下,您需要首先读取并缓冲整个请求正文,然后返回响应并启动一个任务,以在单独的执行中处理该请求。