# 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：

```java
Mono<Ingredient> ingredientMono = webClient
    .get()
    .uri("http://localhost:8080/ingredients/{id}", ingredientId)
    .exchange()
    .flatMap(cr -> cr.bodyToMono(Ingredient.class));
```

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

```java
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 调用像如下这样：

```java
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()` 进一步扁平化映射后再返回。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://potoyang.gitbook.io/spring-in-action-v5/di-11-zhang-kai-fa-xiang-ying-shi-api/11.4-xiang-ying-shi-xiao-fei-rest-api/11.4.5-qing-qiu-zhuan-huan.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
