通过springs`WebClient`进行api调用的正确方法是什么,而忽略结果呢?

时间:2018-07-12 18:47:13

标签: spring spring-webflux

通过springs WebClient进行api调用的正确方法是什么,而忽略结果? ClientResponse对象明确指出,我必须对结果做点事情...

Docs:

  

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

我可以打电话给WebClient并忽略结果吗?还是我可以使用然后忽略的通用“ body或toEntity方法”

1 个答案:

答案 0 :(得分:11)

很好的问题!在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)

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

为什么?因为要使连接正确返回到连接池,所以必须将其保持在干净状态。此时,由于我们在阅读整个正文之前将要关闭,因此无法回收此连接。

TL; DR;如果您100%确信服务器不会发送正文,或者如果您宁愿浪费连接并为创建新的正文付出代价而不是等待读取整个响应正文(特别是如果它很大),请使用此选项。 / p>

服务器正在发送响应正文

现在,如果服务器确实发送了响应正文,而您根本不在乎它,您仍然可以获取该正文,但不执行任何操作,并在完成时收到信号:

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;最后一个选项是安全且经过优化的(但并不十分简洁),但是只要响应主体不是很大,前一个选项就可以很好地实现。