1. 概述
WebClient是Spring WebFlux提供用于http请求的客户端类,它完全非阻塞,等待远程响应的同时,不会阻塞本地正在执行的线程,单位时间内有限资源下支持更高的并发量。
2. 配置
2.1 构建
create方式(默认参数)
WebClient client1 = WebClient.create();
WebClient client2 = WebClient.create("http://192.168.0.108:8082");
builder方式(可调整、补充WebClient的默认参数)
WebClient client = WebClient.builder()
.baseUrl("http://192.168.0.108:8082")
.defaultHeaders( x -> {
x.add("aa", "11");
})
//.clientConnector(new ReactorClientHttpConnector())
.build();
WebClient中的参数,往往作为所有请求的通用配置,默认HTTP客户端配置的是reactor netty。
2.2 缓存区
请求数据包较大时,需要调整 编解码缓冲区大小,以免出现超限异常,默认情况下,这些限制被设置为256KB。
WebClient webClient = WebClient.builder()
.codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(2 * 1024 * 1024))
.build();
2.3 超时
连接超时
HttpClient httpClient = HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000);
WebClient webClient = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
读写超时
HttpClient httpClient = HttpClient.create()
.doOnConnected(conn -> conn
.addHandlerLast(new ReadTimeoutHandler(10))
.addHandlerLast(new WriteTimeoutHandler(10)));
WebClient webClient = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
响应超时(通用)
HttpClient httpClient = HttpClient.create()
.responseTimeout(Duration.ofSeconds(2));
WebClient webClient = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
响应超时(单独)
WebClient.create().get()
.uri("https://example.org/path")
.httpRequest(httpRequest -> {
HttpClientRequest reactorRequest = httpRequest.getNativeRequest();
reactorRequest.responseTimeout(Duration.ofSeconds(2));
})
.retrieve()
.bodyToMono(String.class);
3. 实践
3.1 get请求
WebClient client = WebClient.create("http://192.168.0.108:8082");
Mono<Apple> result = client.get()
.uri("/demo/getInfo?id=1")
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(Apple.class);
// 订阅结果
result.subscribe(System.out::println);
3.2 post请求
WebClient client = WebClient.create("http://192.168.0.108:8082");
Mono<Apple> body = Mono.just(new Apple(1, "xxx"));
Mono<String> result = client.post()
.uri("/demo/postInfo")
.contentType(MediaType.APPLICATION_JSON)
.body(body, Apple.class)
.retrieve()
.bodyToMono(String.class);
// 订阅结果
result.subscribe(System.out::println);
3.3 retrieve获取响应
通过retrieve方式获取响应,可按返回值类型,直接获取结果,上面例子都是该种方式。
3.4 exchange获取响应
通过exchange方式,能获取更多响应细节数据,依据这些数据,可以做个性化的响应处理。
WebClient client = WebClient.create("http://192.168.0.108:8082");
Mono<Apple> result = client.get()
.uri("/demo/getInfo?aa=1")
.accept(MediaType.APPLICATION_JSON)
.exchangeToMono(res -> {
// 获取 statusCode, headers
System.out.println("statusCode: " + res.statusCode());
res.headers().asHttpHeaders()
.forEach((k, v) -> {
System.out.println(String.format("header, %s: %s", k, v));
});
return res.bodyToMono(Apple.class);
});
// 订阅结果
result.subscribe(System.out::println);
3.5 阻塞
block方法,可以同步阻塞方式获取结果。
WebClient client = WebClient.create("http://192.168.0.108:8082");
Apple result = client.get()
.uri("/demo2/getInfo?id=1")
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(Apple.class)
.block();
// 结果
System.out.println(result);
3.6 上下文
WebClient采用异步非阻塞方式,来处理请求、响应,可以通过上下文功能,在贯穿一个请求的整个过程共享该数据,样例如下:
WebClient client = WebClient.create("http://192.168.0.108:8082");
Mono<Apple> result = client.get()
.uri("/demo/getInfo?id=1")
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(Apple.class)
.flatMap(x -> {
return Mono.deferContextual(context -> {
x.setName(context.get("aa") + x.getName());
return Mono.just(x);
});
})
.contextWrite(context -> context.put("aa", "xxx-"));
// 订阅结果
result.subscribe(System.out::println);