12.4.5 请求转换
到目前为止,您已经使用了 WebClient 的 retrieve()
方法来发送请求。在这些情况中,retrieve()
方法返回 ResponseSpec 类型的对象。通过它可以使用 onStatus()
、bodyToFlux()
和 bodyToMono()
等方法处理响应。使用 ResponseSpec 对象适用于简单的一些情况,某些方面会受到限制。举例来说,如果您需要获取响应的 header 或 cookie, 使用 ResponseSpec 就无法完成。
当 ResponseSpec 不满足需求时,可以使用 exchange()
取代 retrieve()
。exchange()
方法返回 ClientResponse 类型的 Mono,您可以应用反应式操作来检查和使用完整的返回数据,包括有效载荷、headers 和 Cookies。
在研究 exchange()
与 retrieve()
的区别之前,让我们先看看他们有多相似。下面的代码片段使用 WebClient 和 exchange()
,按 ID 获取单个 Ingredient:
Mono<Ingredient> ingredientMono = webClient
.get()
.uri("http://localhost:8080/ingredients/{id}", ingredientId)
.exchangeToMono(cr -> cr.bodyToMono(Ingredient.class));
这大致相当于下面使用 retrieve()
的示例:
Mono<Ingredient> ingredientMono = webClient
.get()
.uri("http://localhost:8080/ingredients/{id}", ingredientId)
.retrieve()
.bodyToMono(Ingredient.class);
在 exchangeToMono()
示例中,没有使用 ResponseSpec 对象的 bodyToMono()
获得 Mono<Ingredient>
。而是通过一个扁平化映射函数,将 ClientResponse 映射到 Mono<Ingredient>
,从而得到 Mono<ClientResponse>
,也即一个 Mono。
现在让我们看看 exchangeToMono()
有什么不同之处。让我们假设,请求中可能包含一个名为 X_UNAVAILABLE
的请求头。当其值为 true
时,表示(由于某种原因)相关的 Ingredient 不可用。为了便于讨论,假设该头存在,您肯定希望得到的结果 Mono 为空,不返回任何内容。这可以通过添加另一个对 flatMap()
的调用来实现。整个 WebClient 调用像如下这样:
Mono<Ingredient> ingredientMono = webClient
.get()
.uri("http://localhost:8080/ingredients/{id}", ingredientId)
.exchangeToMono(cr -> {
if (cr.headers().header("X_UNAVAILABLE").contains("true")) {
return Mono.empty();
}
return Mono.just(cr);
})
.flatMap(cr -> cr.bodyToMono(Ingredient.class));
新的 flatMap()
调用,检查给定 ClientRequest 对象的响应头。查找名称为 X_UNAVAILABLE
且值为 true
的 header。如果找到,则返回一个空的 Mono。否则,它将返回一个包含 ClientResponse 的新 Mono 对象。无论是哪种情况,Mono 对象都将通过 flatMap()
进一步扁平化映射后再返回。