本文主要是介绍Spring WebFlux 与 WebClient 使用指南及最佳实践,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
《SpringWebFlux与WebClient使用指南及最佳实践》WebClient是SpringWebFlux模块提供的非阻塞、响应式HTTP客户端,基于ProjectReactor实现,...
Spring WebFlux 与 WebClient 使用指南
1. WebClient 概述
WebClient 是 Spring WebFlux 模块提供的非阻塞、响应式 HTTP 客户端,基于 Project Reactor 实现,适用于高并发场景。
核心优势:
2. 核心依赖配置
在 pom.xml
中添加依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency>
3. WebClient 的创建与配置
3.1 全局配置(推荐)
@Configuration public class WebClientConfig { @Bean public WebClient webClient() { return WebClient.builder() .baseUrl("https://api.example.com") // 基础 URL .defaultHeader("Accept", "application/json") .clientConnector(new ReactorClientHttpConnector( HttpClient.create() .responseTimeout(Duration.ofSeconds(30)) // 响应超时 ) .build(); } }
3.2 临时创建(按需使用)
WebClient client = WebClient.create(www.chinasem.cn"https://api.example.com");
4. 发送 HTTP 请求
4.1 GET 请求(携带 Token)
public Mono<User> getUser(String id, String token) { return webClient.get() .uri("/users/{id}", id) // 路径参数 .header("Token-Test", token) // 自定义 Token .retrieve() .bodyToMono(User.class); // 解析为对象 }
4.2 POST 请求(发送数组 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) // 发送 List 集合 .retrieve() .bodyToMono(String.class); }
5. 错误处理
5.1 HTTP 错误处理(onStatus)
.onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(errorBody -> { String msg = String.format("状态码: %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. 同步与异步调用
6.1 异步调用(subscribe)
webClient.get() .uri("/data") .retrieve() .bodyToMono(String.class) .subscribe( data -> log.info("成功: {}", data), error -> log.error("失败: {}", error) );
6.2 同步调用(block,仅用于测试或特殊场景)
try { String result = webClient.get() .uri("/data") .retrieve() .bodyToMono(String.class) .block(Duration.ofSeconds(10)); // 阻塞等待 } catch (Exception e) { log.error("请求失败", e); }
7. 统一响应结构
7.1 定义统一响应类
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 转换响应
public Mono<ApiResponse<User>> getUser(String id) { return webClient.get() .uri("/users/{id}", id) .retrieve() .bodyToMono(User.class) .map(ApiResponse::success) //China编程 包装为成功响应 .onErrorResume(e -> Mono.just(ApiResponse.error(500, e.getMessage())) ); }
8. 日志与监控
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)) // 响应超时 ) .retryWhen(Retry.backoff(3, Duration.ofSeconds(1))) // 指数退避重试
9.2 连接池配置
HttpClient.create() .baseUrl("https://api.example.com") .tcpConfiguration(tcpClient -> tcpClient.option(Channhttp://www.chinasem.cnelOption.CONNECT_TIMEOUT_MILLIS, 5000) )
10. 常见问题与最佳实践
10.1 避免手动调用subscribe
- 错误示例:
// Service 层中手动调用 subscribe(不推荐) public void sendData() { webClient.post().subscribe(); // 可能导China编程致资源泄漏 }
- 正确做法:
在 Controller 或调用方返回Mono
/Flux
,由框架处理订阅。
10.2 统一异常处理
@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 性能优化
- 复用 WebClient 实例:避免频繁创建新实例。
- 合理设置超时:根据接口 SLA 调整响应和连接超时。
附录:完整代码示例
发送 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"); // 仅测试环境添加 } }) .contentType(MediaType.APPLICATION_JSON) .bodyValue(users) .retrieve() .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(error -> { String msg = String.format("状态码:%d, 错误信息: %s", response.rawStatusCode(), error); log.error(msg); return Mono.error(new RuntimeException(msg)); }) ) .bodyToMono(ApiResponse.class) // 解析为自定义响应对象 // 检查业务状态码 .flatMap(result -> { if (result.getStatusCode() != 200) { String msg = String.format("业务错误: 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 的核心用法、错误处理策略及性能优化技巧。建议结合项目需求灵活调整配置,遵循响应式编程最佳实践。
到此这篇关于Spring WebFlux 与 WebClient 使用指南及最佳实践的文章就介绍到这了,更多相关Spring WebFlux WebClient 使用内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持China编程(www.chinasem.cn)!
这篇关于Spring WebFlux 与 WebClient 使用指南及最佳实践的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!