【问题标题】:Return 404 when a Flux is empty当 Flux 为空时返回 404
【发布时间】:2019-04-25 09:13:42
【问题描述】:

我试图在 Flux 为空时返回 404,类似于此处:WebFlux functional: How to detect an empty Flux and return 404?

我主要担心的是,当您检查通量是否具有元素时,它会发出该值并且您会丢失它。当我尝试在服务器响应上使用 switch if empty 时,它永远不会被调用(我暗中认为这是因为 Mono 不是空的,只有正文是空的)。

我正在做的一些代码(我的 Router 类上有一个过滤器,用于检查 DataNotFoundException 以返回 notFound):

Flux<Location> response = this.locationService.searchLocations(searchFields, pageToken);
return ok()
        .contentType(APPLICATION_STREAM_JSON)
        .body(response, Location.class)
        .switchIfEmpty(Mono.error(new DataNotFoundException("The data you seek is not here.")));

^This 从不调用 switchIfEmpty

Flux<Location> response = this.locationService.searchLocations(searchFields, pageToken);

return response.hasElements().flatMap(l ->{
   if(l){
       return ok()
               .contentType(APPLICATION_STREAM_JSON)
               .body(response, Location.class);
   } 
   else{
       return Mono.error(new DataNotFoundException("The data you seek is not here."));
   }
});

^这会丢失 hasElements 上发出的元素。

有没有办法在 hasElements 中恢复发出的元素或让 switchIfEmpty 只检查正文的内容?

【问题讨论】:

    标签: spring-webflux project-reactor


    【解决方案1】:

    您可以将switchIfEmpty 运算符应用于您的Flux&lt;Location&gt; response。

    Flux<Location> response = this.locationService
            .searchLocations(searchFields, pageToken)
            .switchIfEmpty(Mono.error(new DataNotFoundException("The data you seek is not here.")));
    

    【讨论】:

    • 但是当我这样做的时候,我怎么知道返回哪个状态码呢?响应对象可能是 200 或 404。我错过了什么吗?
    • 你告诉过你有一个过滤器来过滤你的异常。此异常从 Flux 响应传播到 ServerResponse
    • 你是对的!我的代码返回 500 和一条奇怪的错误消息,我调试了问题,发现调用的是 DefaultExceptionHandler,而不是过滤器。 “Just”必须使用我的 ErrorAttributes 版本添加一个全局错误处理程序,以与应用程序的其余部分保持一致。
    【解决方案2】:

    虽然发布的答案确实正确,但如果您只想返回状态代码(加上原因)并且不想摆弄任何自定义过滤器或定义自己的错误响应异常,则可以使用便利异常类。

    另一个好处是您不必将响应包装在任何 ResponseEntity 对象中,虽然在某些情况下很有用(例如,使用位置 URI 创建),但对于简单的状态响应来说有点过头了。

    另见https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/server/ResponseStatusException.html

     return this.locationService.searchLocations(searchFields, pageToken)
            .buffer()
            .switchIfEmpty(Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND, "these are not the droids you are lookig for")));
    

    【讨论】:

      【解决方案3】:

      亚历山大写的是正确的。您在从不为空的对象上调用switchIfEmpty ServerResponse.ok() 根据定义不是一个空的发布者。我喜欢反向处理这种情况,因此调用服务,然后链接所有创建响应的方法。

          this.locationService.searchLocations(searchFields, pageToken)
                  .buffer()
                  .map(t -> ResponseEntity.ok(t))
                  .defaultIfEmpty(ResponseEntity.notFound().build());
      

      更新(不确定是否有效,但试一试):

       public Mono<ServerResponse> myRestMethod(ServerRequest serverRequest) {
              return serverRequest.bodyToMono(RequestDTO.class)
                      .map((request) -> searchLocations(request.searchFields, request.pageToken))
                      .flatMap( t -> ServerResponse
                              .ok()
                              .body(t, ResponseDTO.class)
                      )
                      .switchIfEmpty(ServerResponse.notFound().build())
                      ;
          }
      

      【讨论】:

      • buffer() 不会列出所有元素然后一次性返回吗?如果我可以发出每个元素而不是整个列表,我会更喜欢。
      • 有什么关系。在您从 rest 方法返回的流调用 onComplete 之前,不会发送对客户端的响应。您使用 webflux 的事实并不意味着客户端会收到部分响应。
      • 不是吗?当我卷曲我的响应时,我会以一种一种方式得到 Location 对象。例如,如果 Kafka 服务器调用它,我预计会出现这种情况。
      • 对不起,我转过身来,您在原始帖子中是正确的,响应将在收到时返回给客户。我发布了我认为可以实现您想要的更新。
      猜你喜欢
      • 2018-02-04
      • 1970-01-01
      • 2019-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-22
      • 1970-01-01
      • 2017-10-08
      相关资源
      最近更新 更多