荒原曙光
3.49GB · 2025-11-20
retry、timeout、filter 等,代码更短、更直观正如前文所言,WebClient 位于 spring-webflux 模块,因此只要 webflux starter 即可。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
写一个配置类,把 WebClient 注册成单例 Bean。整个应用只需创建一次,任何地方都可以直接 @Autowired 拿来用,这样既省资源又方便统一配置。配置类的代码示例如下:
@Configuration
public class WebClientConfig {
@Bean // 全局唯一实例,Spring 会把该对象放进容器,任何地方都能注入
public WebClient webClient() {
return WebClient.builder()
.baseUrl("https://httpbin.org") // 公共前缀,可省
.defaultHeader(HttpHeaders.USER_AGENT, "demo-app/1.0")
.build();
}
}
在代码里手动创建一个 WebClient 实例,不交给 Spring 容器托管,也不共享,代码示例如下:
WebClient client = WebClient.create("https://httpbin.org");
当前线程会卡住,直到获取响应结果。
String body = client.get()
.uri("/get?name=Tom")
.retrieve()
.bodyToMono(String.class)
.block(); // 阻塞点
System.out.println("阻塞结果 = " + body);
当前线程执行 subscribe 后就可以去做别的事,获取响应结果后回调执行后续逻辑。
client.get()
.uri("/get?name=Jerry")
.retrieve()
.bodyToMono(String.class)
.subscribe(
json -> System.out.println("异步回调 = " + json), // 成功
err -> err.printStackTrace() // 失败
);
System.out.println("主线程继续执行,不等待");
适用于服务端持续推送数据的场景,如 SSE、大文件、日志流。这里演示 HTTP 长连接 + 无限行 JSON 的流式消费,代码示例如下:
// 假定 httpbin.org 的 /stream/{n} 会一次返回 n 行 JSON
Flux<String> flux = client.get()
.uri("/stream/10") // 10 行数据
.retrieve()
.bodyToFlux(String.class); // 每收到一行就往下游发
flux.doOnNext(line -> System.out.println("收到流 => " + line))
.subscribe();
把 Java 对象序列化成 JSON 发给服务器。.bodyValue() 会将常见类型自动序列化,如 POJO、基本类型、Map、List 和任意 Collection。
Mono<String> resp = client.post()
.uri("/post")
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(new User("Tom", 18)) // 自动序列化成 JSON
.retrieve()
.bodyToMono(String.class);
resp.subscribe(json -> System.out.println("POST-JSON 返回 => " + json));
这样可以同时上传文件 + 文本,代码示例如下:
// 1. 准备 multipart 主体
MultipartBodyBuilder builder = new MultipartBodyBuilder();
builder.part("file", new FileSystemResource("demo.txt")); // 文件
builder.part("desc", "这是说明文字"); // 普通字段
// 2. 发送请求
Mono<String> resp = client.post()
.uri("/post")
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(BodyInserters.fromMultipartData(builder.build()))
.retrieve()
.bodyToMono(String.class);
resp.subscribe(json -> System.out.println("POST-Multipart 返回 => " + json));
下面对 WebClient 链式调用里最常见的 5 个方法进行解释:
uri(String path, Object... vars) 是剩余路径,每次请求都可变,会自动拼在前缀 baseUrl 的后面,最终 URL = baseUrl + uri。代码示例如下:
.uri("/user/{id}", 123) // -> /user/123
retrieve() 是一个无参方法,负责把请求发出去 并拿到完整的 HTTP 响应。默认 4xx/5xx 会抛 WebClientResponseException,如果想自己处理错误,需要使用 exchangeToMono 或 onStatus。
bodyToMono(Class<T> clazz) 会将整个响应体一次性转换成单个对象(Mono),代码示例如下:
.bodyToMono(User.class) // JSON -> User 对象
.bodyToMono(String.class) // 原始文本
bodyToFlux(Class<T> clazz) 会将持续流切成多个对象(Flux),如SSE、大文件分块等场景,代码示例如下:
.bodyToFlux(String.class); // 每收到一行就变成一个 String
subscribe(Consumer<T> onNext, Consumer<Throwable> onError) 会执行整个链式调用,并提供收到数据/出错时的回调。如果不调用 subscribe() 或 block(),整个链式调用不会真正执行。
.subscribe(
user -> log.info("收到用户 {}", user),
ex -> log.error("请求失败", ex)
)
因为懒惰和大大小小的事情,这一篇拖了很久,久到我都忘记了。以下是剩余的问题,原本是拟定作为一级标题进行学习的,只有暂且搁置,以后有机会再进行补习。