知識庫 / Spring / Spring Boot RSS 訂閱

Spring Boot 中 RestClient 指南

REST,Spring Boot
HongKong
11
03:33 AM · Dec 06 ,2025

1. 引言

<emRestClient</em> 是 Spring Framework 6.1 M2 中引入的同步 HTTP 客户端,取代了 <em RestTemplate</em>。同步 HTTP 客户端以阻塞方式發送和接收 HTTP 請求和響應,這意味着它會在每個請求完成之前等待,然後再繼續處理下一個請求。

在本教程中,我們將探索 <em RestClient</em> 的優勢,以及它與 <em RestTemplate</em> 的比較。

2. RestClientRestTemplate

RestTemplate,正如其名稱所示,基於模板設計模式構建而成。這是一種行為設計模式,它在方法中定義算法的骨架,允許子類為某些步驟提供特定的實現。雖然它是一種強大的模式,但它也導致了過載的需求,這可能會帶來不便。

為了改進這一點,RestClient 具有流暢 API 功能。 流暢 API 是一種設計模式,它允許通過在對象上順序調用方法來實現方法鏈,從而使代碼更具可讀性和表達性,通常不需要中間變量。

讓我們從創建一個基本的 RestClient 開始:

RestClient restClient = RestClient.create();

3. 使用 HTTP 請求方法進行簡單的獲取

類似於 <em >RestTemplate</em > 或任何其他 REST 客户端,<em >RestClient</em > 允許我們使用請求方法進行 HTTP 調用。讓我們逐步瞭解不同的 HTTP 方法,用於創建、檢索、修改和刪除資源。

我們將操作一個簡單的 <em >Article</em > 類:

public class Article {
    Integer id;
    String title;
    // constructor and getters
}

3.1. 使用 GET 獲取資源

我們將使用 GET HTTP 方法來請求和從 Web 服務器上的指定資源獲取數據,而不會對其進行修改。 它主要用於 Web 應用程序的只讀操作。

首先,讓我們獲取一個簡單的 String 作為響應,而無需將其序列化到我們的自定義類中:

String result = restClient.get()
  .uri(uriBase + "/articles")
  .retrieve()
  .body(String.class);

3.2. 使用 POST 創建資源

我們將使用 HTTP POST 方法將數據提交到 Web 服務器上的資源,通常用於在 Web 應用程序中創建新的記錄或資源。 與 GET 方法不同,GET 方法用於檢索數據,而 POST 方法旨在將數據發送到服務器進行處理,例如提交 Web 表單。

URI 應該定義我們想要處理的資源。

讓我們將一個 ID 等於 1 的簡單文章發送到我們的服務器:

Article article = new Article(1, "How to use RestClient");
ResponseEntity<Void> response = restClient.post()
  .uri(uriBase + "/articles")
  .contentType(APPLICATION_JSON)
  .body(article)
  .retrieve()
  .toBodilessEntity();

因為我們指定了 “APPLICATION_JSON” 內容類型,Article 類的實例將在 Jackson 庫的底層自動序列化為 JSON。在此示例中,我們使用 toBodilessEntity() 方法忽略響應體。POST 端點通常不需要,並且通常不返回任何負載。

3.3. 使用 PUT 方法更新資源

接下來,我們將探討使用 PUT HTTP 方法來更新或替換現有資源,並提供相應數據。這種方法通常用於修改現有實體或其他 Web 應用程序中的資源。通常,我們需要指定要更新的資源,以確保完全替換。

讓我們修改我們在上一段中所創建的文章。我們提供的 URI 應該標識出我們要更改的資源:

Article article = new Article(1, "How to use RestClient even better");
ResponseEntity<Void> response = restClient.put()
  .uri(uriBase + "/articles/1")
  .contentType(APPLICATION_JSON)
  .body(article)
  .retrieve()
  .toBodilessEntity();

類似於前一個段落,我們將依賴 RestClient 對我們的請求體進行序列化,並忽略響應。

3.4. 使用 DELETE 刪除資源

我們將使用 DELETE HTTP 方法來請求從 Web 服務器刪除指定的資源。 類似於 GET 端點,我們通常不為請求提供任何負載,而是依賴於 URI 中編碼的參數:

ResponseEntity<Void> response = restClient.delete()
  .uri(uriBase + "/articles/1")
  .retrieve()
  .toBodilessEntity();

4. 支持請求屬性

關於對 WebClient 中支持的類型請求屬性的支持,重要的是要理解 WebClient 引入了屬性以解決一個限制,即針對反應式環境的限制。 這種限制是缺乏可靠的線程本地。 由於 RestTemplateRestClient 可以使用線程本地,因此我們很少在這種意義上需要請求屬性。

RestClient 中使用屬性的幾個用例存在,例如將屬性傳遞給攔截器。 為此,Spring Framework 6.2 添加了到 org.springframework.http.HttpRequest 接口的 getAttributes,它返回一個對 HttpRequest 請求的可變屬性映射。 我們可以創建一個攔截器來更新請求屬性:

@Test
void updateRequestAttribute() throws Exception {
    String attrName = "attr1";
    String attrValue = "value1";

    assertDoesNotThrow(() -> { 
      ClientHttpRequestInterceptor interceptor = (request, body, execution) -> {
        request.getAttributes().put(attrName, attrValue);
	return execution.execute(request, body);
      };
    });
}

在大多數其他情況下,我們也可以基於映射,在不使用請求屬性 API 的情況下,構建帶有查詢參數的 URI,例如:

RestClient restClient = RestClient.builder()
    .baseUrl("https://example.com/api")
    .build();

String pathVariable = "pathVariable";
ResponseEntity response = restClient.get()
    .uri(uriBuilder -> uriBuilder
      .path("/" + pathVariable)
      .queryParam("param1", "value1")
      .queryParam("param2", "value2")
      .build())
    .header("Content-Type", "application/json")
    .retrieve()
    .toEntity(String.class)
    .block();

5. 反序列化響應

我們經常希望對請求進行序列化,並將響應反序列化為我們能夠高效操作的類。 RestClient 具備執行 JSON 到對象轉換的功能,該功能由 Jackson 庫提供支持。

此外,由於共享使用消息轉換器,我們可以利用 RestTemplate 支持的所有數據類型。

讓我們通過其 ID 檢索一篇文章,並將其序列化為 Article 類的實例:

Article article = restClient.get()
  .uri(uriBase + "/articles/1")
  .retrieve()
  .body(Article.class);

指定的類在獲取某些泛型類的實例時會稍微複雜一些,例如 List。例如,如果我們想要獲取所有文章,我們會得到 Article>List 對象。在這種情況下,我們可以使用 ParameterizedTypeReference 抽象類來告訴 RestClient 我們將獲得什麼類型的對象。

我們甚至不需要指定泛型類型,Java 會自動為我們推斷類型:

List<Article> articles = restClient.get()
  .uri(uriBase + "/articles")
  .retrieve()
  .body(new ParameterizedTypeReference<>() {});

6. 使用 Exchange 解析響應

RestClient 包含 exchange() 方法,用於處理更復雜的場景,通過提供對底層 HTTP 請求和響應的訪問權限。因此,該庫不會應用默認的處理程序,並且我們必須自己處理狀態碼。

假設我們與通信的服務在數據庫中沒有文章時返回 204 狀態碼。由於這種略微非標準的行為,我們希望以特殊的方式處理它。當狀態碼等於 204 時,我們拋出 ArticleNotFoundException 異常,並且當狀態碼不等於 200 時,也拋出更通用的異常:

List<Article> article = restClient.get()
  .uri(uriBase + "/articles")
  .exchange((request, response) -> {
      if (response.getStatusCode().isSameCodeAs(HttpStatusCode.valueOf(204))) {
          throw new ArticleNotFoundException();
      } else if (response.getStatusCode().isSameCodeAs(HttpStatusCode.valueOf(200))) {
          return objectMapper.readValue(response.getBody(), new TypeReference<>() {});
      } else {
          throw new InvalidArticleResponseException();
      }
});

由於我們正在處理原始響應,因此還需要自己使用 ObjectMapper 解析響應體。

7. 錯誤處理

默認情況下,當 RestClient 遇到 HTTP 響應中 4xx 或 5xx 的狀態碼時,它會拋出一個異常,該異常是 RestClientException 的子類。 我們可以通過實現自定義狀態處理器來覆蓋此行為。

讓我們編寫一個在無法找到文章時拋出自定義異常的狀態處理器:

Article article = restClient.get()
  .uri(uriBase + "/articles/1234")
  .retrieve()
  .onStatus(status -> status.value() == 404, (request, response) -> {
      throw new ArticleNotFoundException(response);
  })
  .body(Article.class);

8. 從 RestClient 構建實例,基於 RestTemplate

RestClientRestTemplate 的後繼者,在較舊的代碼庫中,我們很可能遇到使用 RestTemplate 的實現。

幸運的是,使用舊版本的 RestTemplate 的配置創建 RestClient 實例非常簡單。

RestTemplate oldRestTemplate;
RestClient restClient = RestClient.create(oldRestTemplate);

9. 結論

在本文中,我們重點介紹了 <em style="font-style: italic;">RestClient</em> 類,它是 <em style="font-style: italic;">RestTemplate</em> 的繼任者,作為同步 HTTP 客户端。我們學習瞭如何使用它的流暢 API,用於簡單和複雜的使用案例。接下來,我們開始收集所有 HTTP 方法,然後轉向響應序列化和錯誤處理主題。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.