Spring?WebFlux?與?WebClient?使用指南及最佳實踐
Spring WebFlux 與 WebClient 使用指南
1. WebClient 概述
WebClient 是 Spring WebFlux 模塊提供的非阻塞、響應(yīng)式 HTTP 客戶端,基于 Project Reactor 實現(xiàn),適用于高并發(fā)場景。
核心優(yōu)勢:
- 支持異步非阻塞 I/O,提升吞吐量。
- 鏈式 API 設(shè)計,便于組合操作。
- 集成 Spring 生態(tài),支持自動編解碼(JSON、XML)。
2. 核心依賴配置
在 pom.xml 中添加依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>3. WebClient 的創(chuàng)建與配置
3.1 全局配置(推薦)
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient() {
return WebClient.builder()
.baseUrl("https://api.example.com") // 基礎(chǔ) URL
.defaultHeader("Accept", "application/json")
.clientConnector(new ReactorClientHttpConnector(
HttpClient.create()
.responseTimeout(Duration.ofSeconds(30)) // 響應(yīng)超時
)
.build();
}
}3.2 臨時創(chuàng)建(按需使用)
WebClient client = WebClient.create("https://api.example.com");4. 發(fā)送 HTTP 請求
4.1 GET 請求(攜帶 Token)
public Mono<User> getUser(String id, String token) {
return webClient.get()
.uri("/users/{id}", id) // 路徑參數(shù)
.header("Token-Test", token) // 自定義 Token
.retrieve()
.bodyToMono(User.class); // 解析為對象
}4.2 POST 請求(發(fā)送數(shù)組 Body)
public Mono<String> postUsers(List<User> users, String token) {
return webClient.post()
.uri("/users/batch")
.header("Token-Test", token)
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(users) // 發(fā)送 List 集合
.retrieve()
.bodyToMono(String.class);
}5. 錯誤處理
5.1 HTTP 錯誤處理(onStatus)
.onStatus(HttpStatus::isError, response ->
response.bodyToMono(String.class)
.flatMap(errorBody -> {
String msg = String.format("狀態(tài)碼: %d, 錯誤信息: %s",
response.rawStatusCode(), errorBody);
log.error(msg);
return Mono.error(new ServiceException(msg));
})
)5.2 非 HTTP 錯誤處理(doOnError)
.doOnError(error -> {
if (!(error instanceof ServiceException)) {
log.error("非 HTTP 錯誤: {}", error.getMessage());
}
})6. 同步與異步調(diào)用
6.1 異步調(diào)用(subscribe)
webClient.get()
.uri("/data")
.retrieve()
.bodyToMono(String.class)
.subscribe(
data -> log.info("成功: {}", data),
error -> log.error("失敗: {}", error)
);6.2 同步調(diào)用(block,僅用于測試或特殊場景)
try {
String result = webClient.get()
.uri("/data")
.retrieve()
.bodyToMono(String.class)
.block(Duration.ofSeconds(10)); // 阻塞等待
} catch (Exception e) {
log.error("請求失敗", e);
}7. 統(tǒng)一響應(yīng)結(jié)構(gòu)
7.1 定義統(tǒng)一響應(yīng)類
public class ApiResponse<T> {
private int code;
private String message;
private T data;
public static <T> ApiResponse<T> success(T data) {
return new ApiResponse<>(200, "Success", data);
}
public static <T> ApiResponse<T> error(int code, String message) {
return new ApiResponse<>(code, message, null);
}
}7.2 轉(zhuǎn)換響應(yīng)
public Mono<ApiResponse<User>> getUser(String id) {
return webClient.get()
.uri("/users/{id}", id)
.retrieve()
.bodyToMono(User.class)
.map(ApiResponse::success) // 包裝為成功響應(yīng)
.onErrorResume(e ->
Mono.just(ApiResponse.error(500, e.getMessage()))
);
}8. 日志與監(jiān)控
8.1 成功日志
.doOnSuccess(response ->
log.info("請求成功: {}", response)
)8.2 錯誤日志
.doOnError(error ->
log.error("請求失敗: {}", error.getMessage())
)9. 高級配置
9.1 超時與重試
.clientConnector(new ReactorClientHttpConnector(
HttpClient.create()
.responseTimeout(Duration.ofSeconds(30)) // 響應(yīng)超時
)
.retryWhen(Retry.backoff(3, Duration.ofSeconds(1))) // 指數(shù)退避重試9.2 連接池配置
HttpClient.create()
.baseUrl("https://api.example.com")
.tcpConfiguration(tcpClient ->
tcpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
)10. 常見問題與最佳實踐
10.1 避免手動調(diào)用subscribe
- 錯誤示例:
// Service 層中手動調(diào)用 subscribe(不推薦) public void sendData() { webClient.post().subscribe(); // 可能導(dǎo)致資源泄漏 } - 正確做法:
在 Controller 或調(diào)用方返回Mono/Flux,由框架處理訂閱。
10.2 統(tǒng)一異常處理
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ServiceException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Mono<ApiResponse<?>> handleServiceException(ServiceException e) {
return Mono.just(ApiResponse.error(500, e.getMessage()));
}
}10.3 性能優(yōu)化
- 復(fù)用 WebClient 實例:避免頻繁創(chuàng)建新實例。
- 合理設(shè)置超時:根據(jù)接口 SLA 調(diào)整響應(yīng)和連接超時。
附錄:完整代碼示例
發(fā)送 POST 請求并處理錯誤
public Mono<ApiResponse<String>> syncData(List<User> users, String token) {
String uri = UriComponentsBuilder.fromUriString("https://api.example.com")
.path("/batch")
.queryParam("source", "web")
.queryParamIfPresent("type", Optional.ofNullable("test".equals(activeProfile) ? "test" : null))
.build()
.toUriString();
return webClient.post()
.uri(uri)
.header("Token-Test", token)
.headers(headers -> {
if ("test".equals(activeProfile)) {
headers.add("type", "test"); // 僅測試環(huán)境添加
}
})
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(users)
.retrieve()
.onStatus(HttpStatus::isError, response ->
response.bodyToMono(String.class)
.flatMap(error -> {
String msg = String.format("狀態(tài)碼:%d, 錯誤信息: %s", response.rawStatusCode(), error);
log.error(msg);
return Mono.error(new RuntimeException(msg));
})
)
.bodyToMono(ApiResponse.class) // 解析為自定義響應(yīng)對象
// 檢查業(yè)務(wù)狀態(tài)碼
.flatMap(result -> {
if (result.getStatusCode() != 200) {
String msg = String.format("業(yè)務(wù)錯誤: code=%d, message=%s",
result.getStatusCode(), result.getMessage());
log.error(msg);
return Mono.error(new ServiceException(msg));
}
return Mono.just(result);
})
// 成功記錄日志
.doOnSuccess(success -> log.info("請求成功"))
// 失敗記錄日志
.doOnError(error -> log.error("失敗", error.getMessage()))
.onErrorResume(e ->
Mono.just(ApiResponse.error(500, e.getMessage()))
);
}通過本文檔,您可全面掌握 WebClient 的核心用法、錯誤處理策略及性能優(yōu)化技巧。建議結(jié)合項目需求靈活調(diào)整配置,遵循響應(yīng)式編程最佳實踐。
到此這篇關(guān)于Spring WebFlux 與 WebClient 使用指南及最佳實踐的文章就介紹到這了,更多相關(guān)Spring WebFlux WebClient 使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring?Boot中獲取request的三種方式及請求過程
這篇文章主要介紹了Spring?Boot當中獲取request的三種方式,包括請求過程流程分析及response常用API,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下2022-03-03
hibernate一對多關(guān)聯(lián)映射學(xué)習(xí)小結(jié)
這篇文章主要介紹了hibernate一對多關(guān)聯(lián)映射學(xué)習(xí)小結(jié),需要的朋友可以參考下2017-09-09
JavaFX程序初次運行創(chuàng)建數(shù)據(jù)庫并執(zhí)行建表SQL詳解
這篇文章主要介紹了JavaFX程序初次運行創(chuàng)建數(shù)據(jù)庫并執(zhí)行建表SQL詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-08-08
Springboot實現(xiàn)通用Auth認證的幾種方式
本文主要介紹了Springboot實現(xiàn)通用Auth認證的幾種方式,主要介紹了4種方式,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-07-07
idea兩側(cè)的maven-project-structure圖標不見了如何解決
這篇文章主要介紹了如何解決idea兩側(cè)的maven-project-structure圖標不見了問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07

