对于最新的稳定版本,请使用 Spring Framework 6.2.0! |
REST 客户端
Spring 框架提供了以下选项来调用 REST 端点:
-
WebClient
- 具有 Fluent API 的非阻塞反应式客户端。 -
RestTemplate
- 具有模板方法 API 的同步客户端。 -
HTTP 接口 - 带有生成的动态代理实现的带注释的接口。
WebClient
WebClient
是执行 HTTP 请求的非阻塞反应式客户端。它是
在 5.0 中引入,并提供了 的替代方案,支持
同步、异步和流式处理方案。RestTemplate
WebClient
支持以下内容:
-
非阻塞 I/O。
-
反应流背压。
-
高并发性,硬件资源较少。
-
函数式的 Fluent API,利用 Java 8 lambda。
-
同步和异步交互。
-
向服务器流式传输或从服务器向式传输。
有关更多详细信息,请参阅 WebClient 。
RestTemplate
它通过 HTTP 客户端库提供更高级别的 API。它使它
易于在单行中调用 REST 端点。它公开了以下几组
重载方法:RestTemplate
RestTemplate 处于维护模式,仅请求次要
要接受的更改和错误。请考虑改用 WebClient。 |
“方法”组 | 描述 |
---|---|
|
通过 GET 检索表示形式。 |
|
使用 GET 检索 (即 status、headers 和 body)。 |
|
使用 HEAD 检索资源的所有标头。 |
|
使用 POST 创建新资源,并从响应中返回标头。 |
|
使用 POST 创建新资源,并从响应中返回表示形式。 |
|
使用 POST 创建新资源,并从响应中返回表示形式。 |
|
使用 PUT 创建或更新资源。 |
|
使用 PATCH 更新资源并从响应中返回表示形式。
请注意,JDK 不支持 ,但 Apache
HttpComponents 和其他组件可以。 |
|
使用 DELETE 删除指定 URI 处的资源。 |
|
使用 ALLOW 检索资源允许的 HTTP 方法。 |
|
上述方法的更通用(且不那么固执己见)版本,它提供额外的
需要时灵活。它接受一个(包括 HTTP 方法、URL、标头、
和 body 作为输入)并返回一个 . 这些方法允许使用 of 而不是来指定
具有泛型的响应类型。 |
|
执行请求的最通用方式,可完全控制请求 通过回调接口进行准备和响应提取。 |
初始化
默认构造函数用于执行请求。您可以
切换到具有 .
目前,还内置了对 Apache HttpComponents 和 OkHttp 的支持。java.net.HttpURLConnection
ClientHttpRequestFactory
例如,要切换到 Apache HttpComponents,您可以使用以下内容:
RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
每个都公开了特定于底层的配置选项
HTTP 客户端库 — 例如,用于凭证、连接池和其他详细信息。ClientHttpRequestFactory
请注意,HTTP 请求的实现可能会在以下情况下引发异常
访问表示错误的响应的状态(如 401)。如果这是一个
问题,请切换到另一个 HTTP 客户端库。java.net |
RestTemplate 可以进行检测以实现可观测性,以便生成指标和跟踪。
请参阅 RestTemplate 可观察性支持部分。 |
URI
许多方法接受 URI 模板和 URI 模板变量。
作为变量参数,或作为 .RestTemplate
String
Map<String,String>
以下示例使用 variable 参数:String
String result = restTemplate.getForObject(
"https://example.com/hotels/{hotel}/bookings/{booking}", String.class, "42", "21");
以下示例使用 :Map<String, String>
Map<String, String> vars = Collections.singletonMap("hotel", "42");
String result = restTemplate.getForObject(
"https://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars);
请记住,URI 模板是自动编码的,如下例所示:
restTemplate.getForObject("https://example.com/hotel list", String.class);
// Results in request to "https://example.com/hotel%20list"
您可以使用 的 属性来自定义 URI 的方式
进行编码。或者,您可以准备 a 并将其传递到
接受 .uriTemplateHandler
RestTemplate
java.net.URI
RestTemplate
URI
有关使用 URI 和编码 URI 的更多详细信息,请参阅 URI 链接。
头
您可以使用这些方法指定请求标头,如下例所示:exchange()
String uriTemplate = "https://example.com/hotels/{hotel}";
URI uri = UriComponentsBuilder.fromUriString(uriTemplate).build(42);
RequestEntity<Void> requestEntity = RequestEntity.get(uri)
.header("MyRequestHeader", "MyValue")
.build();
ResponseEntity<String> response = template.exchange(requestEntity, String.class);
String responseHeader = response.getHeaders().getFirst("MyResponseHeader");
String body = response.getBody();
您可以通过返回 .RestTemplate
ResponseEntity
身体
传入方法和从方法返回的对象将与原始对象相互转换
content 在 .RestTemplate
HttpMessageConverter
在 POST 上,输入对象将序列化为请求正文,如下例所示:
URI location = template.postForLocation("https://example.com/people", person);
您无需显式设置请求的 Content-Type 标头。在大多数情况下,
您可以根据源类型和所选的
Message Converter 会相应地设置内容类型。如有必要,您可以使用这些方法显式提供请求标头,并在
turn 影响选择的消息转换器。Object
exchange
Content-Type
在 GET 上,响应的主体被反序列化为 output ,如下例所示:Object
Person person = restTemplate.getForObject("https://example.com/people/{id}", Person.class, 42);
不需要显式设置请求的标头。在大多数情况下,
可以根据预期的响应类型找到兼容的消息转换器,该
然后帮助填充标题。如有必要,您可以使用这些方法显式提供标头。Accept
Accept
exchange
Accept
默认情况下,注册所有内置的消息转换器,具体取决于有帮助的 Classpath 检查
来确定存在哪些可选的转换库。您还可以设置消息
转换器来显式使用。RestTemplate
消息转换
该模块包含用于读取和
通过 和 编写 HTTP 请求和响应的正文。 实例在客户端使用(例如,在 ) 和
在服务器端(例如,在 Spring MVC REST 控制器中)。spring-web
HttpMessageConverter
InputStream
OutputStream
HttpMessageConverter
RestTemplate
框架中提供了主媒体 (MIME) 类型的具体实现
,并且默认情况下,分别在 Client 端和 Server 端注册(请参阅 配置消息转换器)。RestTemplate
RequestMappingHandlerAdapter
的实现在以下各节中介绍。
对于所有转换器,都使用默认媒体类型,但您可以通过设置 bean 属性来覆盖它。下表描述了每种实现:HttpMessageConverter
supportedMediaTypes
消息转换器 | 描述 |
---|---|
|
可以从 HTTP 读取和写入实例的实现
请求和响应。默认情况下,此转换器支持所有文本媒体类型
() 并使用 的 a 进行写入。 |
|
可以从 HTTP 读取和写入表单数据的实现
请求和响应。默认情况下,此转换器读取和写入媒体类型。表单数据从 .转换器还可以写入(但不能读取)multipart
从 .默认情况下,是
支持。从 Spring Framework 5.2 开始,可以支持其他多部分子类型
写入表单数据。有关更多详细信息,请参阅 javadoc。 |
|
可以从
HTTP 请求和响应。默认情况下,此转换器支持所有媒体类型 ()
并使用 的 a 写入。您可以覆盖此
通过设置属性并覆盖 . |
|
可以使用 Spring 和包中的抽象来读取和写入 XML 的实现。
此转换器需要 and 才能使用。您可以注入这些
通过 constructor 或 bean 属性。默认情况下,此转换器支持 和 。 |
|
可以使用 Jackson 的 .您可以根据需要使用 Jackson 的
提供的注释。当您需要进一步控制时(对于自定义 JSON
需要为特定类型提供序列化器/反序列化器),你可以通过 property 注入自定义。默认情况下,此
转换器支持 . |
|
一种可以使用 Jackson XML 扩展的 .您可以根据需要通过使用 JAXB 来自定义 XML 映射
或 Jackson 提供的注释。当您需要进一步控制时(对于自定义 XML
需要为特定类型提供序列化器/反序列化器),你可以通过 property 注入自定义。默认情况下,此
转换器支持 . |
|
可以从 HTTP 请求和响应中读取和写入的实现。仅支持 、 和 。默认情况下,此转换器支持 和 。 |
|
可以从 HTTP 请求和响应中读取和写入的实现。此转换器读取
并写入 Java I/O API 支持的媒体类型。 |
Jackson JSON 视图
您可以指定 Jackson JSON 视图以仅序列化对象属性的子集,如下例所示:
MappingJacksonValue value = new MappingJacksonValue(new User("eric", "7!jd#h23"));
value.setSerializationView(User.WithoutPasswordView.class);
RequestEntity<MappingJacksonValue> requestEntity =
RequestEntity.post(new URI("https://example.com/user")).body(value);
ResponseEntity<String> response = template.exchange(requestEntity, String.class);
多部分
要发送多部分数据,您需要提供其值
可以是 for part 内容、for file part 或 for
带有标题的 part 内容。例如:MultiValueMap<String, Object>
Object
Resource
HttpEntity
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
parts.add("fieldPart", "fieldValue");
parts.add("filePart", new FileSystemResource("...logo.png"));
parts.add("jsonPart", new Person("Jason"));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
parts.add("xmlPart", new HttpEntity<>(myBean, headers));
在大多数情况下,您不必为每个部分指定 。内容
type 根据选择要序列化的
it 或者,在 a 的情况下基于文件扩展名。如有必要,您可以
显式提供 with 包装器。Content-Type
HttpMessageConverter
Resource
MediaType
HttpEntity
一旦 准备好了,你可以把它传递给 ,如下所示:MultiValueMap
RestTemplate
MultiValueMap<String, Object> parts = ...;
template.postForObject("https://example.com/upload", parts, Void.class);
如果 包含至少一个非值,则设置
到 由 .如果 has 值 ,则默认为 。
如有必要,也可以显式设置 。MultiValueMap
String
Content-Type
multipart/form-data
FormHttpMessageConverter
MultiValueMap
String
Content-Type
application/x-www-form-urlencoded
Content-Type
HTTP 接口
Spring Framework 允许您将 HTTP 服务定义为带有注释的 Java 接口 方法进行 HTTP 交换。然后,您可以生成实现此接口的代理 并执行交换。这有助于简化 HTTP 远程访问,这通常 涉及一个 Facade,该 Facade 包装了使用底层 HTTP 客户端的详细信息。
第一,使用方法声明一个接口:@HttpExchange
interface RepositoryService {
@GetExchange("/repos/{owner}/{repo}")
Repository getRepository(@PathVariable String owner, @PathVariable String repo);
// more HTTP exchange methods...
}
第二,创建一个代理,该代理将执行声明的 HTTP 交换:
WebClient client = WebClient.builder().baseUrl("https://api.github.com/").build();
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(client)).build();
RepositoryService service = factory.createClient(RepositoryService.class);
@HttpExchange
在类型级别受支持,它适用于所有方法:
@HttpExchange(url = "/repos/{owner}/{repo}", accept = "application/vnd.github.v3+json")
interface RepositoryService {
@GetExchange
Repository getRepository(@PathVariable String owner, @PathVariable String repo);
@PatchExchange(contentType = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
void updateRepository(@PathVariable String owner, @PathVariable String repo,
@RequestParam String name, @RequestParam String description, @RequestParam String homepage);
}
方法参数
带注释的 HTTP 交换方法支持灵活的方法签名,包括以下内容 方法参数:
Method 参数 | 描述 |
---|---|
|
动态设置请求的 URL,覆盖 annotation 的属性。 |
|
动态设置请求的 HTTP 方法,覆盖 Comments 的属性 |
|
添加一个或多个请求标头。参数可以是 a 或具有多个标头、a of 值或
individual value 的非 String 值支持类型转换。 |
|
在请求 URL 中添加用于扩展占位符的变量。参数可以是具有多个变量的 a,也可以是单个值。类型转换
支持非 String 值。 |
|
将请求的主体作为要序列化的对象或
支持反应式流(如 、 或任何其他异步类型)
通过配置的 . |
|
添加一个或多个请求参数。参数可以是具有多个参数的 a 或、值 a 或
单个值。非 String 值支持类型转换。 当设置为 , 请求
参数在请求正文中编码。否则,它们将被添加为 URL 查询
参数。 |
|
添加请求部分,可以是 String (表单字段)、(文件部分)、
对象(要编码的实体,例如作为 JSON),(部分内容和标题),
a Spring ,或上述任何一种的反应流。 |
|
添加一个或多个 Cookie。参数可以是 a 或包含多个 cookie、a of 值或
individual value 的非 String 值支持类型转换。 |
返回值
带注释的 HTTP 交换方法支持以下返回值:
方法返回值 | 描述 |
---|---|
|
执行给定的请求,并发布响应内容(如果有)。 |
|
执行给定的请求,释放响应内容(如果有),并返回 响应标头。 |
|
执行给定的请求并将响应内容解码为声明的返回类型。 |
|
执行给定的请求,并将响应内容解码为声明的 元素类型。 |
|
执行给定的请求,并释放响应内容(如果有),并返回带有 status 和 headers 的 a。 |
|
执行给定的请求,将响应内容解码为声明的返回类型,然后
返回 A 以及 status、Headers 和 Decoded 正文。 |
|
执行给定的请求,将响应内容解码为声明的
元素类型,并返回带有 status、headers 和 decoded 的
响应正文流。 |
您还可以使用在 .ReactiveAdapterRegistry |
异常处理
默认情况下,引发 4xx 和 5xx HTTP 状态
代码。要自定义此功能,您可以注册一个适用于所有
通过客户端执行的响应:WebClient
WebClientResponseException
WebClient webClient = WebClient.builder()
.defaultStatusHandler(HttpStatusCode::isError, resp -> ...)
.build();
WebClientAdapter clientAdapter = WebClientAdapter.forClient(webClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory
.builder(clientAdapter).build();
有关更多详细信息和选项(例如禁止显示错误状态代码),请参阅 中的 Javadoc。defaultStatusHandler
WebClient.Builder