RestTemplate 中的 exchange()、postForEntity() 和 execute() 區別

HTTP Client-Side,REST,Spring
Remote
1
04:44 AM · Dec 01 ,2025

1. 簡介

在 Spring 生態系統中,有一類名為 RestTemplate 的類。 該實用類是用於發送 HTTP 消息和處理響應的高級類

在本教程中,我們將探討 exchange()postForEntity()execute() 方法之間的差異,這些方法是 RestTemplate 類中的。

2. 何為 RestTemplate?

如上所述,RestTemplate 是 Spring Framework 中的一個實用類,它簡化了發送 HTTP 消息和處理響應的過程。 RestTemplate 類非常適合編寫簡單的 HTTP 客户端,因為它提供了許多功能:

  • 支持所有標準 HTTP 動詞 (GET, POST 等)
  • 能夠處理所有標準 MIME 類型 (JSON, XML, 形式編碼等)
  • 高層 API 允許我們與 Java 類一起工作,並避免複雜的序列化問題
  • 可以使用 ClientHttpRequestInitializerClientHttpRequestInterceptor 接口進行自定義

2.1. 棄用警告

從 Spring Framework 5 開始,RestTemplate 類正在逐漸被棄用。 雖然它仍然存在於 Spring Framework 6 中,但維護者明確表示此類的未來增強不會被接受。

由於僅接受 minor bug 和安全修復,建議開發者使用 WebClient 代替。 此類具有更現代的 API,並支持同步、異步和流式使用案例。

3. 基本 RestTemplate 使用

RestTemplate 使得使用標準 HTTP 動詞 通過提供具有相應名稱的公共方法變得容易。

例如,要發送 GET 請求,我們可以使用具有 getFor 前綴的許多重載方法。 還有其他 HTTP 動詞(包括 POST、PUT、DELETE、HEAD 和 PATCH)的類似公共方法。

所有這些方法的結構幾乎相同。 它們基本上只需要有關要發送的 URL 以及請求和響應正文的表示形式的信息。 頭部信息會自動為我們創建。

雖然這些高級方法使編寫 HTTP 客户端變得非常容易,但現實世界並不總是符合 HTTP 規範。 在某些情況下,我們可能需要構建一個不完全符合任何特定動詞方法的 HTTP 請求

這就是為什麼 RestTemplate 提供了具有粒度方法的通用方法,我們將會在下一部分中探討這些方法。

4. 使用 exchange()postForEntity()execute() 方法

雖然使用頂層動詞特定方法對於許多用例來説是可以的,但我們很可能會需要對 RestTemplate 生成的 HTTP 請求進行更多控制。 這就是 exchange()execute() 方法發揮作用的地方。

讓我們考慮一個 HTTP POST 請求,它允許我們創建一個新的圖書數據庫條目。 以下是一個封裝請求主體所需的所有數據的 Java 類:

class Book {
  String title;
  String author;
  int yearPublished;
}

下面,我們將使用三個 RestTemplate 方法變體之一來發送此請求。

4.1. 使用 postForEntity() 方法

第一個也是最簡單的方法是使用 postForEntity()此方法僅需要 URL 和請求主體,並解析響應主體為 ResponseEntity 對象

Book book = new Book(
  "Cruising Along with Java",
  "Venkat Subramaniam",
  2023);
 ResponseEntity<Book> response = restTemplate.postForEntity(
  "https://api.bookstore.com", 
  book, 
  Book.class);

在此示例中,我們創建了一個新的書對象,將其發送到服務器,並將響應解析回另一個書對象。 值得注意的是,我們只需要提供遠程 URL、請求對象和用於響應的類。 其他一切,包括 HTTP 標頭,都是 RestTemplate 自動構建的。

4.2. 使用 exchange() 方法

我們可以通過使用 exchange() 方法來發送請求的下一種方式:

Book book = new Book(
  "Effective Java",
  "Joshua Bloch",
  2001);

HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth("username", "password");

ResponseEntity<Book> response = restTemplate.exchange(
  "https://api.bookstore.com",
  HttpMethod.POST,
  new HttpEntity<>(book, headers),
  Book.class);

主要區別在於,我們用 HttpEntity 包裝請求主體,而不是傳遞一個簡單的 Java 對象。 這允許我們使用請求中設置額外的 HTTP 標頭。

另一個明顯的不同之處在於,exchange() 方法是通用的,這意味着它可用於任何 HTTP 方法。 因此,請求方法的第二個參數必須指示用於請求的方法。

4.3. 使用 execute() 方法

發送 POST 請求的最後一種方式是使用 execute() 方法。 此方法是最通用的,而且實際上是所有其他方法內部使用的底層方法。

以下是使用 execute() 方法發送 POST 請求的高級示例:

ResponseEntity<Book> response = restTemplate.execute(
    "https://api.bookstore.com",
    HttpMethod.POST,
    new RequestCallback() {
        @Override
        public void doWithRequest(ClientHttpRequest request) throws IOException {
            // manipulate request headers and body
        }
    },
    new ResponseExtractor<ResponseEntity<Book>>() {
        @Override
        public ResponseEntity<Book> extractData(ClientHttpResponse response) throws IOException {
            // manipulate response and return ResponseEntity
        }
    }
);

值得注意的是,雖然我們仍然需要提供 URL 和 HTTP 方法,但其他一切看起來大不相同。 這是因為 execute() 方法不直接處理請求和響應。

它允許我們使用 RequestCallbackResponseExtractor 接口創建和修改它們。 最大的好處是 這使我們能夠對請求和響應對象具有最大的控制權。 然而,我們的代碼不太簡潔,並且我們丟失了其他 RestTemplate 方法提供的許多自動功能。

值得注意的是,RestTemplate 確實提供了一個用於輕鬆創建 RequestCallback 實例的工廠方法。 該方法是 httpEntityCallback(),它具有兩個重載形式,可以幫助我們減少使用 execute() 方法時編寫代碼量:

Book book = new Book(
  "Reactive Spring",
  "Josh Long",
  2020);
        
RequestCallback requestCallback1 = restTemplate.httpEntityCallback(book);
RequestCallback requestCallback2 = restTemplate.httpEntityCallback(book, Book.class);

同樣,RestTemplate 提供了用於快速創建 ResponseExtractor 實例的工廠方法:

ResponseExtractor<ResponseEntity<Book>> responseExtractor = restTemplate.responseEntityExtractor(Book.class);

當然,使用這兩個工廠方法會使我們失去使用 execute() 方法的任何好處。 如果我們選擇同時使用它們,我們最好只使用動詞特定方法或 exchange() 方法。

5. 結論

在本文中,我們探討了使用 RestTemplate 發送 HTTP POST 請求的三種不同方法。首先,我們看到了如何使用特定動詞的 postForEntity() 方法來創建小而簡潔的 HTTP 請求。然後,我們研究了兩種替代方法,exchange()execute(),用於發送相同的請求。

儘管這三種方法都產生相同的結果,但它們各自具有優缺點。 postForEntity() 方法產生了更少的代碼,但這意味着我們對生成的 HTTP 請求的控制力較弱。 exchange()execute() 方法則提供了我們對請求的更多控制權,但代價是我們的代碼更冗長,並且不太依賴於 Spring 框架的自動功能。

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

發佈 評論

Some HTML is okay.