Spring Boot 异步HTTP客户端配置使用
1. 添加依赖
如果是 Spring Boot 2.x 或 3.x,WebClient 已包含在 spring-boot-starter-webflux 中:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>2. WebClient 配置
可以通过 Bean 全局配置,也可以直接使用 WebClient.create()。
2.1 全局 Bean 配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient(WebClient.Builder builder) {
return builder
.baseUrl("https://api.example.com") // 可配置默认 baseUrl
.build();
}
}2.2 自定义连接池和超时(高级配置)
import reactor.netty.http.client.HttpClient;
import reactor.netty.resources.ConnectionProvider;
import java.time.Duration;
@Bean
public WebClient webClient() {
ConnectionProvider provider = ConnectionProvider.builder("custom")
.maxConnections(100)
.pendingAcquireTimeout(Duration.ofSeconds(60))
.build();
HttpClient httpClient = HttpClient.create(provider)
.responseTimeout(Duration.ofSeconds(5));
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
}3. 异步调用示例
WebClient 默认就是异步非阻塞的(基于 Reactor 响应式流)。
3.1 GET 请求
@Autowired
private WebClient webClient;
public Mono<String> getDataAsync() {
return webClient.get()
.uri("/data")
.retrieve()
.bodyToMono(String.class);
}3.2 POST 请求
public Mono<ResponseDto> postDataAsync(RequestDto request) {
return webClient.post()
.uri("/submit")
.bodyValue(request)
.retrieve()
.bodyToMono(ResponseDto.class);
}3.3 在 Controller 中使用
@RestController
public class DemoController {
@Autowired
private WebClient webClient;
@GetMapping("/call-remote")
public Mono<String> callRemote() {
return webClient.get()
.uri("/remote-api")
.retrieve()
.bodyToMono(String.class);
}
}4. 异步并发请求
比如同时请求多个接口并合并结果:
Mono<String> call1 = webClient.get().uri("/api1").retrieve().bodyToMono(String.class);
Mono<String> call2 = webClient.get().uri("/api2").retrieve().bodyToMono(String.class);
Mono<Tuple2<String, String>> result = Mono.zip(call1, call2);5. 错误处理
webClient.get().uri("/api")
.retrieve()
.onStatus(HttpStatus::isError, response ->
response.bodyToMono(String.class)
.flatMap(errorBody -> Mono.error(new RuntimeException(errorBody)))
)
.bodyToMono(String.class);6. 配置超时和连接池参数
如前文 2.2,使用 Reactor Netty 的 ConnectionProvider 和 HttpClient 可以灵活设置连接数、超时等。
7. 其他常见配置
- 代理设置
- SSL 配置
- 请求/响应日志
- 拦截器(ExchangeFilterFunction)
例如日志拦截器:
WebClient.builder()
.filter((request, next) -> {
System.out.println("Request: " + request.url());
return next.exchange(request);
})
.build();8. 与 Spring MVC Controller 集成
如果你用的是 Spring MVC Controller,可以用 Mono<T> 或 Flux<T> 作为返回值,Spring Boot 会自动处理响应式类型。
9. 自定义请求头、参数、Cookie
设置请求头/参数:
webClient.get()
.uri(uriBuilder -> uriBuilder
.path("/search")
.queryParam("keyword", "spring")
.build())
.header("Authorization", "Bearer xxx")
.cookie("SESSIONID", "abcdefg")
.retrieve()
.bodyToMono(String.class);10. 全局异常处理与重试机制
全局异常处理:
可以通过 ExchangeFilterFunction 实现全局异常拦截与处理:
@Bean
public WebClient webClient() {
return WebClient.builder()
.filter((request, next) -> next.exchange(request)
.flatMap(response -> {
if (response.statusCode().isError()) {
return response.bodyToMono(String.class)
.flatMap(errorBody -> Mono.error(new RuntimeException(errorBody)));
}
return Mono.just(response);
}))
.build();
}重试机制(reactor-retry):
import reactor.util.retry.Retry;
webClient.get()
.uri("/unstable-api")
.retrieve()
.bodyToMono(String.class)
.retryWhen(Retry.fixedDelay(3, Duration.ofSeconds(2)));11. 文件上传与下载(异步)
文件上传(multipart/form-data):
import org.springframework.core.io.FileSystemResource;
FileSystemResource file = new FileSystemResource("/path/to/file.txt");
webClient.post()
.uri("/upload")
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(BodyInserters.fromMultipartData("file", file))
.retrieve()
.bodyToMono(String.class);文件下载:
webClient.get()
.uri("/download")
.retrieve()
.bodyToFlux(DataBuffer.class)
.map(dataBuffer -> {
// 将 DataBuffer 写入文件
// 省略具体实现
return dataBuffer;
});12. 与服务发现、负载均衡集成
如果用 Spring Cloud,可直接注入带负载均衡的 WebClient:
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
@Bean
@LoadBalanced
public WebClient.Builder loadBalancedWebClientBuilder() {
return WebClient.builder();
}
// 使用
@Autowired
private WebClient.Builder webClientBuilder;
webClientBuilder.build()
.get()
.uri("http://service-name/api")
.retrieve()
.bodyToMono(String.class);这里的 service-name 是注册中心(如 Eureka、Nacos)中的服务名,WebClient 会自动负载均衡。
13. 与 OAuth2 等安全机制集成
Spring Security 提供了对 OAuth2 的支持,可以自动为 WebClient 请求加上 Token。
import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction;
@Bean
public WebClient webClient(ReactiveOAuth2AuthorizedClientManager manager) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2 =
new ServerOAuth2AuthorizedClientExchangeFilterFunction(manager);
return WebClient.builder()
.apply(oauth2.oauth2Configuration())
.build();
}14. WebClient 性能调优建议
- 连接池参数调整合理设置最大连接数、每主机最大连接数、连接超时等
- 响应式编程配合线程池对于非响应式 Controller 推荐
@Async或线程池配合 - 避免阻塞操作在响应式流中避免
block(),否则会失去异步性能优势 - 合理的重试和超时防止雪崩和资源耗尽
15. 常见问题解答
Q1:WebClient 如何同步调用?A:可以用 .block(),但这会阻塞线程,失去异步优势。一般只在测试或特殊场景下使用。
Q2:如何打印 WebClient 的请求和响应日志?A:可通过 ExchangeFilterFunction 实现,或配置日志框架:
logging.level.reactor.netty.http.client=DEBUG
Q3:WebClient 与 RestTemplate 区别?
- RestTemplate 是同步阻塞的
- WebClient 是异步非阻塞的,支持响应式流
- 官方推荐新项目优先用 WebClient
总结
- 推荐使用 WebClient 作为 Spring Boot 异步 HTTP 客户端
- 支持灵活配置连接池、超时、代理、SSL 等
- 默认就是异步非阻塞
- 适合高并发、微服务场景
- WebClient 支持丰富的异步 HTTP 场景,配置灵活
- 可与 Spring Cloud、Spring Security 等生态无缝集成
- 适合微服务、网关、爬虫等高并发异步场景
到此这篇关于Spring Boot 异步HTTP客户端配置使用的文章就介绍到这了,更多相关Spring Boot 异步HTTP内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Java中ByteArrayInputStream和ByteArrayOutputStream用法详解
这篇文章主要介绍了Java中ByteArrayInputStream和ByteArrayOutputStream用法详解, ByteArrayInputStream 的内部额外的定义了一个计数器,它被用来跟踪 read() 方法要读取的下一个字节2022-06-06
IDEA下创建SpringBoot+MyBatis+MySql项目实现动态登录与注册功能
这篇文章主要介绍了IDEA下创建SpringBoot+MyBatis+MySql项目实现动态登录与注册功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2021-02-02
java如何将一个float型数的整数部分和小数分别输出显示
这篇文章主要介绍了java如何将一个float型数的整数部分和小数分别输出显示,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2022-07-07


最新评论