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内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论