WebCLient 概述

WebClient 是一个接口,表示执行 Web 请求的主要入口点。
是 Spring Web Reactive 模块的一部分,用于取代经典的 RestTemplate。此外,这个新的客户端是一个基于 HTTP/1.1 协议的响应式、非阻塞解决方案。


该接口只有一个实现,即我们将要使用的 DefaultWebClient 类

使用

  1. 引入依赖
    spring-boot-starter-webflux
  2. 使用 maven 构建
1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

使用

创建实例

  1. 使用 WebClient 对象
1
WebClient client = WebClient.create();
  1. 使用给定的 url 初始化
1
WebClient client = WebClient.create("http://localhost:8080");
  1. *使用 DefaultWebClientBuilder 类来构建
    推荐使用:可以自定义 WebClient 实例
1
2
3
4
5
6
WebClient client = WebClient.builder()
.baseUrl("http://localhost:8080")
.defaultCookie("cookieKey", "cookieValue")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.defaultUriVariables(Collections.singletonMap("url", "http://localhost:8080"))
.build();

指定超出时间

通常情况下,默认的 30 秒 HTTP 超时时间太慢,无法满足需要,要自定义这种行为,可以创建一个 HttpClient 实例,并配置 WebClient 使用它。


  • 通过 ChannelOption.CONNECT_TIMEOUT_MILLIS 选项设置连接超时。
  • 分别使用 ReadTimeoutHandler 和写 WriteTimeoutHandler 设置读、写超时。
  • 使用 responseTimeout 指令配置响应超时。

配置:在 HttpClient 实例中指定

1
2
3
4
5
6
7
8
9
10
HttpClient httpClient = HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
.responseTimeout(Duration.ofMillis(5000))
.doOnConnected(conn ->
conn.addHandlerLast(new ReadTimeoutHandler(5000, TimeUnit.MILLISECONDS))
.addHandlerLast(new WriteTimeoutHandler(5000, TimeUnit.MILLISECONDS)));

WebClient client = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();

这是 Mono / Flux Publisher 的超时。

定义方法

调用 method(HttpMethod method) 来指定请求的 HTTP 方法:

1
2
3
4
// 方式一
UriSpec<RequestBodySpec> uriSpec = client.method(HttpMethod.POST);
// 方式二
UriSpec<RequestBodySpec> uriSpec = client.post();

定义 url

实现:

1
2
3
4
5
6
7
// 方式一 :作为字符串传递
RequestBodySpec bodySpec = uriSpec.uri("/resource");

// 方式二 :调用UriBuilder接口
```java
RequestBodySpec bodySpec = uriSpec.uri(
uriBuilder -> uriBuilder.pathSegment("/resource").build());

定义请求体

1
2
3
4
5
6
7
8
9
10
11
12
13
// bodyValue 方法
RequestHeadersSpec<?> headersSpec = bodySpec.bodyValue("data");

// Reactor 实例,也可以使用 BodyInserters#fromPublisher
RequestHeadersSpec headersSpec = bodySpec.body(
BodyInserters.fromPublisher(Mono.just("data")),
String.class);

LinkedMultiValueMap map = new LinkedMultiValueMap();
map.add("key1", "value1");
map.add("key2", "value2");
RequestHeadersSpec<?> headersSpec = bodySpec.body(
BodyInserters.fromMultipartData(map));

定义 Header

示例:

1
2
3
4
5
6
7
ResponseSpec responseSpec = headersSpec.header(
HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)
.acceptCharset(StandardCharsets.UTF_8)
.ifNoneMatch("*")
.ifModifiedSince(ZonedDateTime.now())
.retrieve();

获取响应

方式一:

1
2
3
4
5
6
7
8
9
10
Mono<String> response = headersSpec.exchangeToMono(response -> {
if (response.statusCode().equals(HttpStatus.OK)) {
return response.bodyToMono(String.class);
} else if (response.statusCode().is4xxClientError()) {
return Mono.just("Error response");
} else {
return response.createException()
.flatMap(Mono::error);
}
});

方式二:

1
2
Mono<String> response = headersSpec.retrieve()
.bodyToMono(String.class);

WebTestClient

WebTestClient 是测试 WebFlux 服务器端点的主要入口。它的 API 与 WebClient 非常相似,它将大部分工作委托给内部 WebClient 实例,主要侧重于提供测试上下文。DefaultWebTestClient 类是 WebTestClient 的唯一接口实现。

绑定到服务器

1
2
3
4
WebTestClient testClient = WebTestClient
.bindToServer()
.baseUrl("http://localhost:8080")
.build();

绑定到路由

1
2
3
4
5
6
7
8
9
10
11
RouterFunction function = RouterFunctions.route(
RequestPredicates.GET("/resource"),
request -> ServerResponse.ok().build()
);

WebTestClient
.bindToRouterFunction(function)
.build().get().uri("/resource")
.exchange()
.expectStatus().isOk()
.expectBody().isEmpty();

绑定到 WebHandler

绑定到 ApplicationContext

绑定到 Controller

1
2
3
4
@Autowired
private Controller controller;

WebTestClient testClient = WebTestClient.bindToController(controller).build();

发起请求

构建 WebTestClient 对象后,所有后续操作都与 WebClient 类似,直到 exchange 方法(获取响应的一种方法),该方法提供了 WebTestClient.ResponseSpec 接口,可使用诸如 expectStatus、expectBody 和 expectHeader 等有用的方法进行操作:

1
2
3
4
5
6
7
8
9
10
WebTestClient
.bindToServer()
.baseUrl("http://localhost:8080")
.build()
.post()
.uri("/resource")
.exchange()
.expectStatus().isCreated()
.expectHeader().valueEquals("Content-Type", "application/json")
.expectBody().jsonPath("field").isEqualTo("value");