RestTemplate 中 exchange()、postForEntity() 和 execute() 之间的区别
1、简介
在本教程中,我们将了解 RestTemplate
类中 exchange()
、postForEntity()
和 execute()
方法之间的区别。
2、RestTemplate
是啥?
RestTemplate
是 Spring 框架 中的一个工具类,它能让发送 HTTP 消息和处理响应变得简单。RestTemplate
类提供了许多功能,非常适合编写简单的 HTTP 客户端:
- 支持所有标准 HTTP 方法(GET、POST 等)。
- 能够处理所有标准 MIME Type(JSON、XML、表单等)。
- 高级 API 允许我们使用 Java 代码进行配置,并避免复杂的序列化问题。
- 可使用
ClientHttpRequestInitializer
和ClientHttpRequestInterceptor
接口进行自定义。
2.1、废弃警告
从 Spring 5 开始,RestTemplate
类逐渐被弃用。虽然它在 Spring 6 中仍然存在,但维护者已经明确表示,该类今后不会再有任何改进,只接受较小的错误和安全修复。
因此,我们鼓励开发人员使用 WebClient
。该类拥有更现代的 API,支持同步、异步和 stream 场景。
3、RestTemplate
基本用法
RestTemplate
通过提供具有相应名称的 public
方法,让使用标准 HTTP 方法变得简单。
例如,要发送 GET
请求,我们可以使用带有 getFor
前缀的多种重载方法之一。其他 HTTP 方法也类似,包括 POST
、PUT
、DELETE
、HEAD
和 PATCH
。
所有这些方法的结构几乎相同。它们基本上只需要有关的 URL
信息,以及请求和响应体的表示方法。header 等信息会自动生成。
虽然这些高级方法让编写 HTTP 客户端变得非常容易,但现实世界并不总是像 HTTP 规范那样。在某些情况下,我们可能需要构建一个不完全符合特定 HTTP 方法的 HTTP 请求。
这就是为什么 RestTemplate
提供了很多粗粒度的通用方法的原因,接下来我们将了解这些方法。
4、使用 exchange()
、postForEntity()
和 execute()
方法
使用预定义的各种 HTTP 请求方法很方便,但有时我们可能需要对 RestTemplate
生成的 HTTP 请求进行更多控制。这时,exchange()
和 execute()
方法就派上用场了。
让我们举一个 HTTP POST 请求的例子,下面是一个 Java 类,它封装了请求体所需的所有数据:
class Book {
String title;
String author;
int yearPublished;
}
下面我们将分别使用三种 RestTemplate
方法来发送此请求。
4.1、使用 postForEntity()
方法
发送 POST 请求的第一种也是最简单的方法是使用 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);
在这个示例中,我们创建了一个新的 book 对象,将其发送到服务器,然后将响应解析为另一个 book 对象。值得注意的是,我们只需提供远程 URL、请求对象和响应使用的类。其他一切,包括 HTTP Header 信息,都是由 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);
这里的主要区别在于,我们不是传递一个普通的 Java 对象作为请求体,而是用 HttpEntity
对其进行封装。这样,我们就可以在请求中明确设置额外的 HTTP 请求头信息。
另一个明显的区别是,exchange()
方法是通用的,这意味着它可以用于任何 HTTP 方法。因此,URL 后的第二个参数必须指明请求使用的方法。
4.3、使用 execute()
方法
最后一种方式是使用 execute()
方法。这种方法是最通用的,事实上,它是 RestTemplate
中所有其他方法使用的底层方法。
下面是如何使用 execute()
方法发送 POST 请求的示例:
ResponseEntity<Book> response = restTemplate.execute(
"https://api.bookstore.com",
HttpMethod.POST,
new RequestCallback() {
@Override
public void doWithRequest(ClientHttpRequest request) throws IOException {
// 操作请求头和请求体
}
},
new ResponseExtractor<ResponseEntity<Book>>() {
@Override
public ResponseEntity<Book> extractData(ClientHttpResponse response) throws IOException {
// 操作响应并返回 ResponseEntity
}
}
);
值得注意的是,虽然我们仍然需要提供 URL 和 HTTP 方法,但其他一切看起来都大不相同。这是因为 execute()
方法并不直接处理请求和响应。
相反,它让我们能够分别使用 RequestCallback
和 ResponseExtractor
接口来创建和修改它们。这样做的主要好处是,我们可以最大程度地控制请求和响应对象。弊端就是,我们的代码不够简洁,而且失去了许多其他 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);
5、总结
在本文中,我们了解了使用 RestTemplate
发送 HTTP POST 请求的三种不同方法。首先,我们了解了如何使用特定于方法的 postForEntity()
方法来创建小而简洁的 HTTP 请求。然后,我们学习了两种替代方法 exchange()
和 execute()
来发送相同的请求。
虽然这三种方法都能产生相同的结果,但它们各有利弊。postForEntity()
方法产生的代码较少,但我们对结果 HTTP 请求的控制却较弱。exchange()
和 execute()
方法为我们提供了对请求的更多控制,但代价是我们的代码更加冗长,对 Spring 框架自动功能的依赖性也更低。
参考:https://www.baeldung.com/spring-resttemplate-exchange-postforentity-execute