Spring Boot 中的 RestClient 指南
一、簡介
RestClient
是 Spring Framework 6.1 M2 中引入的同步 HTTP 用戶端,它取代了RestTemplate
。同步 HTTP 用戶端以阻塞方式傳送和接收 HTTP 請求和回應,這表示它會等待每個請求完成,然後再繼續處理下一個請求。
在本文中,我們將探討RestClient
提供的功能以及它與RestTemplate
的比較。
RestClient
和RestTemplate
RestTemplate
,顧名思義,是建立在模板設計模式之上的。它是一種行為設計模式,在方法中定義演算法的骨架,允許子類別為某些步驟提供特定的實作。雖然它是一個強大的模式,但它會產生重載的需求,這可能會造成不便。
為了改進這一點, RestClient
提供了流暢的 API。流暢的 API 是一種設計模式,它允許方法鏈接,透過順序呼叫物件上的方法,使程式碼更具可讀性和表現力,通常不需要中間變數。
讓我們從創建一個基本的RestClient
開始:
RestClient restClient = RestClient.create();
3. 使用 HTTP 請求方法簡單取得
與RestTemplate
或任何其他 REST 用戶端類似, RestClient
允許我們使用請求方法進行 HTTP 呼叫。讓我們逐步了解建立、檢索、修改和刪除資源的不同 HTTP 方法。
我們將操作一個基本的Article
類別:
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 建立資源
我們使用 POST HTTP 方法將資料提交到 Web 伺服器上的資源,通常是為了在 Web 應用程式中建立新記錄或資源。與檢索資料的 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. 反序列化響應
我們經常希望序列化請求並將回應反序列化到某個我們可以有效操作的類別。 RestClient
具有執行 JSON 到物件轉換的能力,這是由 Jackson 函式庫提供支援的功能。
此外,由於訊息轉換器的共享利用,我們可以使用RestTemplate
支援的所有資料類型。
讓我們透過 ID 檢索一篇文章並將其序列化為Article
類別的實例:
Article article = restClient.get()
.uri(uriBase + "/articles/1")
.retrieve()
.body(Article.class);
當我們想要取得像List
這樣的泛型類別的實例時,指定主體的類別會稍微複雜一些。例如,如果我們想要取得所有文章,我們將取得List<Article>
物件。在這種情況下,我們可以使用ParameterizedTypeReference
抽象類別來告訴RestClient
我們將獲得什麼物件。
我們甚至不需要指定泛型類型,Java 會為我們推斷類型:
List<Article> articles = restClient.get()
.uri(uriBase + "/articles")
.retrieve()
.body(new ParameterizedTypeReference<>() {});
5. 使用 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
自己反序列化回應的主體。
6. 錯誤處理
預設情況下,當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);
7. 從RestTemplate
建構RestClient
RestClient
是RestTemplate,
在較舊的程式碼庫中,我們很可能會遇到使用RestTemplate
的實作。
幸運的是,使用舊RestTemplate
的配置來建立RestClient
實例非常簡單:
RestTemplate oldRestTemplate;
RestClient restClient = RestClient.create(oldRestTemplate);
八、結論
在本文中,我們研究了RestClient
類,它是作為同步 HTTP 用戶端的RestTemplate
的繼承者。我們學習瞭如何將其流暢的 API 用於簡單和複雜的用例。我們開始匯總所有 HTTP 方法,然後轉向回應序列化和錯誤處理主題。
與往常一樣,所有程式碼範例都可以在 GitHub 上找到。