RestClient 和 WebClient 在異常處理上的具體差異
RestClient 和 WebClient 在異常處理上有顯著的不同,這些差異主要體現(xiàn)在異常處理機(jī)制、錯(cuò)誤處理的復(fù)雜性和靈活性上。以下是兩者的詳細(xì)對(duì)比:【起飛嘎嘎飛LSIXSO】
一、RestClient 的異常處理
(一)異常處理機(jī)制
RestClient 提供了改進(jìn)的錯(cuò)誤處理機(jī)制,使得異常處理和 HTTP 狀態(tài)碼的管理變得更加簡(jiǎn)單和直接。RestClient 在接收到客戶(hù)端錯(cuò)誤狀態(tài)碼(400-499)或服務(wù)器錯(cuò)誤狀態(tài)碼(500-599)時(shí),會(huì)拋出 RestClientException 的子類(lèi)。
(二)自定義錯(cuò)誤處理器
RestClient 支持通過(guò) defaultStatusHandler 方法定義全局的錯(cuò)誤處理器,也可以通過(guò) onStatus 方法為特定請(qǐng)求定義錯(cuò)誤處理器。例如:
java復(fù)制
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();
在運(yùn)行刪除命令行運(yùn)行程序后,控制臺(tái)的輸出如下:
復(fù)制
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"}
另一種選擇是為刪除操作實(shí)現(xiàn) onStatus 方法。它優(yōu)先于 RestClient 默認(rèn)處理程序行為:
java復(fù)制
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();
現(xiàn)在控制臺(tái)中的消息將是:Couldn't delete Not Found
(三)優(yōu)點(diǎn)
- 簡(jiǎn)化錯(cuò)誤處理:RestClient 提供了改進(jìn)的錯(cuò)誤處理機(jī)制,使得異常處理和 HTTP 狀態(tài)碼的管理變得更加簡(jiǎn)單和直接。
- 靈活的錯(cuò)誤處理器:支持全局和局部的錯(cuò)誤處理器,可以根據(jù)需要靈活配置。
(四)缺點(diǎn)
- 功能有限:雖然 RestClient 提供了改進(jìn)的錯(cuò)誤處理機(jī)制,但其功能相對(duì) WebClient 較為有限。
二、WebClient 的異常處理
(一)異常處理機(jī)制
WebClient 提供了強(qiáng)大的錯(cuò)誤處理功能,支持響應(yīng)式編程模型。WebClient 的錯(cuò)誤處理通常使用 onErrorResume、onErrorReturn 等操作符。例如:
java復(fù)制
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() 方法被調(diào)用兩次,一次針對(duì) 4xx 客戶(hù)端錯(cuò)誤,一次針對(duì) 5xx 服務(wù)器錯(cuò)誤。onStatus() 每次調(diào)用都采用兩個(gè)參數(shù):
- Predicate:確定錯(cuò)誤狀態(tài)代碼是否與條件匹配。
- Function:用于返回 Mono,即要傳播到訂閱者的錯(cuò)誤信息。
- 如果狀態(tài)代碼與條件匹配,Mono 則會(huì)發(fā)出相應(yīng)的狀態(tài)代碼,并且 Mono 鏈會(huì)因錯(cuò)誤而終止。在此示例中,Mono 將發(fā)出一條 RuntimeException 錯(cuò)誤消息,指示該錯(cuò)誤是客戶(hù)端錯(cuò)誤還是服務(wù)器錯(cuò)誤。
(二)錯(cuò)誤處理的復(fù)雜性
WebClient 的錯(cuò)誤處理可能更復(fù)雜,需要開(kāi)發(fā)者在處理響應(yīng)狀態(tài)、異常和重試機(jī)制時(shí)更加小心和全面。例如,以下代碼展示了如何處理成功響應(yīng)和錯(cuò)誤:
java復(fù)制
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");
}
}
}
}
);
(三)優(yōu)點(diǎn)
- 強(qiáng)大的錯(cuò)誤處理:WebClient 提供了強(qiáng)大的錯(cuò)誤處理功能,支持響應(yīng)式編程模型。
- 靈活的錯(cuò)誤處理:支持 onErrorResume、onErrorReturn 等操作符,可以靈活處理不同類(lèi)型的錯(cuò)誤。
(四)缺點(diǎn)
- 復(fù)雜性較高:WebClient 的錯(cuò)誤處理可能更復(fù)雜,需要開(kāi)發(fā)者在處理響應(yīng)狀態(tài)、異常和重試機(jī)制時(shí)更加小心和全面。
三、總結(jié)
RestClient 和 WebClient 在異常處理上有顯著的不同:
- RestClient:提供了改進(jìn)的錯(cuò)誤處理機(jī)制,使得異常處理和 HTTP 狀態(tài)碼的管理更加簡(jiǎn)單和直接。它支持全局和局部的錯(cuò)誤處理器,可以根據(jù)需要靈活配置。
- WebClient:提供了強(qiáng)大的錯(cuò)誤處理功能,支持響應(yīng)式編程模型。它支持 onErrorResume、onErrorReturn 等操作符,可以靈活處理不同類(lèi)型的錯(cuò)誤。但其錯(cuò)誤處理可能更復(fù)雜,需要開(kāi)發(fā)者在處理響應(yīng)狀態(tài)、異常和重試機(jī)制時(shí)更加小心和全面。
- 如果你的應(yīng)用場(chǎng)景需要更簡(jiǎn)單的錯(cuò)誤處理機(jī)制,RestClient 是一個(gè)不錯(cuò)的選擇。如果你需要更強(qiáng)大的錯(cuò)誤處理功能,特別是響應(yīng)式編程支持,WebClient 更適合。