RestClient 和 WebClient 在异常处理上的具体差异
RestClient 和 WebClient 在异常处理上有显著的不同,这些差异主要体现在异常处理机制、错误处理的复杂性和灵活性上。以下是两者的详细对比:【起飞嘎嘎飞LSIXSO】
一、RestClient 的异常处理
(一)异常处理机制
RestClient 提供了改进的错误处理机制,使得异常处理和 HTTP 状态码的管理变得更加简单和直接。RestClient 在接收到客户端错误状态码(400-499)或服务器错误状态码(500-599)时,会抛出 RestClientException 的子类。
(二)自定义错误处理器
RestClient 支持通过 defaultStatusHandler 方法定义全局的错误处理器,也可以通过 onStatus 方法为特定请求定义错误处理器。例如:
java复制
RestClient restClient = RestClient.builder()
.baseUrl(properties.getUrl())
.defaultHeader(HttpHeaders.AUTHORIZATION, encodeBasic("pig", "pig"))
.defaultStatusHandler(
HttpStatusCode::is4xxClientError,
(request, response) -> {
logger.error("Client Error Status " + response.getStatusCode());
logger.error("Client Error Body " + new String(response.getBody().readAllBytes()));
}
)
.build();
在运行删除命令行运行程序后,控制台的输出如下:
复制
Client Error Status 404 NOT_FOUND
Client Error Body {"status":404,"message":"Entity Customer for id 2 was not found.","timestamp":"2023-07-23T09:24:55.4088208"}
另一种选择是为删除操作实现 onStatus 方法。它优先于 RestClient 默认处理程序行为:
java复制
ResponseEntity response = restClient.delete()
.uri("/{id}", 2)
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.onStatus(HttpStatusCode::is4xxClientError,
(req, res) -> logger.error("Couldn't delete " + res.getStatusText())
)
.toBodilessEntity();
现在控制台中的消息将是:Couldn't delete Not Found
(三)优点
- 简化错误处理:RestClient 提供了改进的错误处理机制,使得异常处理和 HTTP 状态码的管理变得更加简单和直接。
- 灵活的错误处理器:支持全局和局部的错误处理器,可以根据需要灵活配置。
(四)缺点
- 功能有限:虽然 RestClient 提供了改进的错误处理机制,但其功能相对 WebClient 较为有限。
二、WebClient 的异常处理
(一)异常处理机制
WebClient 提供了强大的错误处理功能,支持响应式编程模型。WebClient 的错误处理通常使用 onErrorResume、onErrorReturn 等操作符。例如:
java复制
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
public static Mono<String> makePostRequestAsync(String url, String postData) {
WebClient webClient = WebClient.builder()
.baseUrl(url)
.build();
return webClient.post()
.uri("/")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.body(BodyInserters.fromFormData("data", postData))
.retrieve()
.onStatus(HttpStatus::is4xxClientError, clientResponse -> Mono.error(new RuntimeException("Client error")))
.onStatus(HttpStatus::is5xxServerError, clientResponse -> Mono.error(new RuntimeException("Server error")))
.bodyToMono(String.class);
}
在此示例中,onStatus() 方法被调用两次,一次针对 4xx 客户端错误,一次针对 5xx 服务器错误。onStatus() 每次调用都采用两个参数:
- Predicate:确定错误状态代码是否与条件匹配。
- Function:用于返回 Mono,即要传播到订阅者的错误信息。
- 如果状态代码与条件匹配,Mono 则会发出相应的状态代码,并且 Mono 链会因错误而终止。在此示例中,Mono 将发出一条 RuntimeException 错误消息,指示该错误是客户端错误还是服务器错误。
(二)错误处理的复杂性
WebClient 的错误处理可能更复杂,需要开发者在处理响应状态、异常和重试机制时更加小心和全面。例如,以下代码展示了如何处理成功响应和错误:
java复制
responseMono.subscribe(
response -> {
// handle the response
LOG.info("SUCCESS API Response {}", response);
},
error -> {
// handle the error
LOG.error("An error occurred: {}", error.getMessage());
LOG.error("error class: {}", error.getClass());
// Errors / Exceptions from Server
if (error instanceof WebClientResponseException) {
WebClientResponseException webClientResponseException =
(WebClientResponseException) error;
int statusCode = webClientResponseException.getStatusCode().value();
String statusText = webClientResponseException.getStatusText();
LOG.info("Error status code: {}", statusCode);
LOG.info("Error status text: {}", statusText);
if (statusCode >= 400 && statusCode < 500) {
LOG.info(
"Error Response body {}", webClientResponseException.getResponseBodyAsString());
}
Throwable cause = webClientResponseException.getCause();
LOG.error("webClientResponseException");
if (null != cause) {
LOG.info("Cause {}", cause.getClass());
if (cause instanceof ReadTimeoutException) {
LOG.error("ReadTimeout Exception");
}
if (cause instanceof TimeoutException) {
LOG.error("Timeout Exception");
}
}
}
// Client errors i.e. Timeouts etc -
if (error instanceof WebClientRequestException) {
LOG.error("webClientRequestException");
WebClientRequestException webClientRequestException =
(WebClientRequestException) error;
Throwable cause = webClientRequestException.getCause();
if (null != cause) {
LOG.info("Cause {}", cause.getClass());
if (cause instanceof ReadTimeoutException) {
LOG.error("ReadTimeout Exception");
}
if (cause instanceof ConnectTimeoutException) {
LOG.error("Connect Timeout Exception");
}
}
}
}
);
(三)优点
- 强大的错误处理:WebClient 提供了强大的错误处理功能,支持响应式编程模型。
- 灵活的错误处理:支持 onErrorResume、onErrorReturn 等操作符,可以灵活处理不同类型的错误。
(四)缺点
- 复杂性较高:WebClient 的错误处理可能更复杂,需要开发者在处理响应状态、异常和重试机制时更加小心和全面。
三、总结
RestClient 和 WebClient 在异常处理上有显著的不同:
- RestClient:提供了改进的错误处理机制,使得异常处理和 HTTP 状态码的管理更加简单和直接。它支持全局和局部的错误处理器,可以根据需要灵活配置。
- WebClient:提供了强大的错误处理功能,支持响应式编程模型。它支持 onErrorResume、onErrorReturn 等操作符,可以灵活处理不同类型的错误。但其错误处理可能更复杂,需要开发者在处理响应状态、异常和重试机制时更加小心和全面。
- 如果你的应用场景需要更简单的错误处理机制,RestClient 是一个不错的选择。如果你需要更强大的错误处理功能,特别是响应式编程支持,WebClient 更适合。