# 11.4.1 通过 GET 方式获取资源

作为使用 WebClient 的样例，假设你需要通过 Taco Cloud API 根据 ID 获取 Ingredient 对象。如果使用 RestTemplate，那么你可能会使用 `getForObject()` 方法。但是，借助 WebClient 的话，你可以构建请求、获取响应并抽取一个会发布 Ingredient 对象的 Mono：

```java
Mono<Ingredient> ingredient = WebClient.create()   
  .get()   
  .uri("http://localhost:8080/ingredients/{id}", ingredientId)   
  .retrieve()   
  .bodyToMono(Ingredient.class);  
ingredient.subscribe(i -> { ... })
```

​ 在这里，你使用 `create()` 创建了一个新的 WebClient 实例。然后，你可以使用 `get()` 和 `uri()` 定义对 [http://localhost:8080/ingredients/{id}](http://localhost:8080/ingredients/%7Bid%7D) 的 GET 请求，其中 {id} 占位符将会被 ingredientId 的值所替换。接着，`retrieve()` 会执行请求。最后，我们调用 `bodyToMono()`将响应体的载荷抽取到 `Mono<Ingredient>` 中，就可以继续使用 Mono 的额外操作了。

​ 为了对 `bodyToMono()` 返回 Mono 进行额外的操作，需要注意的很重要的一点是要在请求发送之前对其进行订阅。发送请求获取值的集合是非常容易的。例如，如下的代码片段将获取所有 Ingredient:

```java
Flux<Ingredient> ingredients = WebClient.create()   
  .get()
  .uri("http://localhost:8080/ingredients") 
  .retrieve()   
  .bodyToFlux(Ingredient.class); 
ingredients.subscribe(i -> { ... })
```

​ 大部分而言，获取多个条目与获取单个条目是相同的。最大的差异在于我们不再是使用 `bodyToMono()` 将响应体抽取为 Mono，而是使用 `bodyToFlux()` 将其抽取为一个 Flux。与 `bodyToMono()` 类似，`bodyToFlux()` 返回的 Flux 还没有被订阅。在数据流过之前，你可以对 Flux 添加一些额外的操作（过滤、映射等）。因此，非常重要的一点就是要订阅结果所形成的 Flux，否则请求将始终不会发送。

### 使用基础 URI 发送请求

​ 你可能会发现在很多请求中都会使用一个通用的基础 URI。这样的话，创建 WebClient bean 的时候设置一个基础 URI 并将其注入到所需的地方是非常有用的。这样的 bean 可以按照如下的方式来声明：

```java
@Bean 
public WebClient webClient() {  
  return WebClient.create("http://localhost:8080"); 
}
```

​ 然后，在想要使用基础 URI 的任意地方，你都可以将 WebClient bean 注入进来并按照如下的方式来使用：

```java
@Autowired 
WebClient webClient; 
public Mono<Ingredient> getIngredientById(String ingredientId) {
  Mono<Ingredient> ingredient = webClient   
    .get() 
    .uri("/ingredients/{id}", ingredientId)  
    .retrieve()  
    .bodyToMono(Ingredient.class);  
	ingredient.subscribe(i -> { ... }) 
}
```

​ 因为 WebClient 已经创建好了，所以你可以通过 `get()` 方法直接使用它。对于 URI 来说，你只需要调用 `uri()` 指定相对于基础 URI 的相对路径即可。

### 对长时间运行的请求进行超时处理

​ 你需要考虑的一件事情就是，网络并不是始终可靠的，或者并不像你预期的那么快，远程服务器在处理请求时有可能会非常缓慢。理想情况下，对远程服务的请求会在一个合理的时间内返回。无法正常返回的话，客户端要是能够避免陷入长时间等待响应的窘境就好了。为了避免客户端请求被缓慢的网络或服务阻塞，你可以使用 Flux 或 Mono 的 `timeout()` 方法，为等待数据发布的过程设置一个时长限制。作为样例，你可以考虑一下如何为获取配料数据使用 `timeout()` 方法：

```java
Flux<Ingredient> ingredients = WebClient.create() 
  .get()   
  .uri("http://localhost:8080/ingredients")  
  .retrieve()   
  .bodyToFlux(Ingredient.class);  
ingredients.timeout(Duration.ofSeconds(1))  
  .subscribe(   
  	i -> { ... },  
  	e -> {    
      // handle timeout error   
    })
```

​ 可以看到，在订阅 Flux 之前，调用了 `timeout()` 方法，将持续时间设置成了 1 秒。如果请求能够在 1 秒之内返回，就不会有任何问题。但是，如果请求花费的时间超过 1s，则会超时，然后会调用 `subscribe()` 的第二个参数进行错误处理。


---

# 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.1-tong-guo-get-fang-shi-huo-qu-zi-yuan.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.
