代码之家  ›  专栏  ›  技术社区  ›  Rylander

通过Springs的“webclient”进行API调用,但忽略结果的正确方法是什么?

  •  3
  • Rylander  · 技术社区  · 6 年前

    通过Spring进行API调用的正确方法是什么 WebClient ,但忽略结果?这个 ClientResponse 对象特别指出我必须对结果做些什么…

    Docs:

    注意:当通过webclient exchange()方法授予对clientresponse的访问权限时,必须始终使用body或toEntity方法之一,以确保释放资源并避免HTTP连接池的潜在问题。如果不需要响应内容,则可以使用BodyToMono(void.class)。但是请记住,如果响应确实包含内容,则连接将关闭,不会放回池中。

    我可以打一个WebClient调用并忽略结果吗?还是有一个通用的catch all “身体或脚趾方法” 我可以使用然后忽略?

    1 回复  |  直到 6 年前
        1
  •  11
  •   Brian Clozel    6 年前

    很好的问题!在JavaDoc中解释这一点有点棘手-请随意创建一个问题 https://jira.spring.io 或者,如果你对如何改进这一点有想法,就发送一个请求。

    有几种方法可以做到这一点,但最佳解决方案取决于您的用例。

    服务器未发送响应正文

    如果您确定服务器没有发送响应主体,或者您希望尽快完成该请求,请使用 bodyToMono(Void.class) 可能是个不错的选择。

    Mono<Void> result = webClient.post()
                    .contentType(MediaType.TEXT_PLAIN)
                    .syncBody("Spring WebFlux")
                    .retrieve().bodyToMono(Void.class);
    
    // you can then chain the result with result.then(otherMono)
    

    缺点是-如果服务器正在发送响应主体,SpringWebFlux将停止读取它并取消底层发布服务器-这将立即关闭HTTP连接,并且不会返回到客户端使用的连接池。

    为什么?因为要将连接正确地返回到连接池,必须将其保持在干净状态;此时,由于在读取整个主体之前要关闭,因此无法回收此连接。

    tl;dr;如果您100%确信服务器不会发送一个主体,或者如果您宁愿浪费连接并支付创建新主体的代价,而不是等待并读取整个响应主体,特别是当它相当大的时候。

    服务器正在发送响应正文

    现在,如果服务器确实发送了一个响应主体,而您只是不关心它,那么您仍然可以提取主体,但不做任何处理,并在完成后获得一个信号:

    Mono<String> result = webClient.post()
                    .contentType(MediaType.TEXT_PLAIN)
                    .syncBody("Spring WebFlux")
                    .retrieve().bodyToMono(String.class);
    
    // you can then chain the result with result.then(otherMono) or result.then()
    

    现在让我们假设响应体非常大,您不想用 String 或Java对象。在这种情况下,您可以降低到 DataBuffer (字节缓冲区的Spring抽象,可用于提高内存效率)。

    Mono<Void> result = webClient.post()
                    .contentType(MediaType.TEXT_PLAIN)
                    .syncBody("Spring WebFlux")
                    .retrieve()
                    // we're getting a Flux<DataBuffer>
                    .bodyToFlux(DataBuffer.class)
                    // they might be pooled so we need to release them to avoid memory leaks
                    .map(DataBufferUtils::release)
                    .then();
    

    tl;dr;最后一个选项是安全的和优化的(但它并不是很简洁),但是前一个选项是完美的,只要响应主体不是超大的。