11.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)
    .exchange()
    .flatMap(cr -> cr.bodyToMono(Ingredient.class));

这大致相当于下面使用 retrieve() 的示例:

Mono<Ingredient> ingredientMono = webClient
    .get()
    .uri("http://localhost:8080/ingredients/{id}", ingredientId)
    .retrieve()
    .bodyToMono(Ingredient.class);

exchange() 示例中,没有使用 ResponseSpec 对象的 bodyToMono() 获得 Mono<Ingredient>。而是通过一个扁平化映射函数,将 ClientResponse 映射到 Mono<Ingredient>,从而得到 Mono<ClientResponse> ,也即一个 Mono。

现在让我们看看 exchange() 有什么不同之处。让我们假设,请求中可能包含一个名为 X_UNAVAILABLE 的请求头。当其值为 true 时,表示(由于某种原因)相关的 Ingredient 不可用。为了便于讨论,假设该头存在,您肯定希望得到的结果 Mono 为空,不返回任何内容。这可以通过添加另一个对 flatMap() 的调用来实现。整个 WebClient 调用像如下这样:

Mono<Ingredient> ingredientMono = webClient
    .get()
    .uri("http://localhost:8080/ingredients/{id}", ingredientId)
    .exchange()
    .flatMap(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() 进一步扁平化映射后再返回。

最后更新于