我们正在将org.springframework.web.reactive.function.client.WebClient
与reactor.netty.http.client.HttpClient
作为Spring 5.1.9的一部分,使用exchange()
方法发出请求。此方法的documentation突出显示以下内容:
...使用exchange()时,这是应用程序的责任消耗任何响应内容,而不考虑场景(成功,错误,意外数据等)。否则会导致内存泄漏。
我们对exchange()
的使用是相当基本的,但是错误场景的文档对我来说并不明确,我想确定我们已经为所有结果正确释放了资源。本质上,我们有一个阻塞实现,该实现发出一个请求并返回ResponseEntity
,而不管响应代码如何:
try {
...
ClientResponse resp = client.method(method).uri(uri).syncBody(body).exchange().block();
ResponseEntity<String> entity = resp.toEntity(String.class).block();
return entity;
} catch (Exception e) {
// log error details, return internal server error
}
[如果我了解实现方法,则无论响应代码如何(例如4xx,5xx),如果成功分派了请求,exchange()
都会始终给我们答复。在这种情况下,我们只需要调用toEntity()
即可使用响应。我担心的是错误情况(例如无响应,低级别的连接错误等)。上面的异常处理是否可以捕获所有其他场景,并且它们中的任何一个都有需要使用的响应吗?
注意:ClientResponse.releaseBody()
仅在5.2中引入
发出请求时必须使用响应,但是如果您不能执行请求,则可能在之前引发了异常,并且响应不会有问题。
在文档中说:
注意:通过WebClient exchange()方法使用ClientResponse时,必须使用以下方法之一来确保主体已被消耗或释放:
- body(BodyExtractor)
- bodyToMono(Class)或bodyToMono(ParameterizedTypeReference)
- bodyToFlux(Class)或bodyToFlux(ParameterizedTypeReference)
- toEntity(Class)或toEntity(ParameterizedTypeReference)
- toEntityList(Class)或toEntityList(ParameterizedTypeReference)
- toBodilessEntity()
- releaseBody()
如果没有期望的响应内容,也可以使用bodyToMono(Void.class)。但是请记住,如果有任何内容到达,连接将被关闭,而不是放回池中。这与releaseBody()的确相反,后者确实消耗了整个主体并释放了接收到的所有内容。
您可以尝试使用.retrieve()代替.exchange()并根据自己的喜好处理错误。
public Mono<String> someMethod() {
return webClient.method(method)
.uri(uri)
.retrieve()
.onStatus(
(HttpStatus::isError), // or the code that you want
(it -> handleError(it.statusCode().getReasonPhrase())) //handling error request
)
.bodyToMono(String.class);
}
private Mono<? extends Throwable> handleError(String message) {
log.error(message);
return Mono.error(Exception::new);
}
在此示例中,我使用了Exception,但是您可以创建一些更具体的异常,然后使用某些异常处理程序返回所需的http状态。不建议使用块,更好的方法是将流向前传递。