对于最新的稳定版本,请使用 Spring Framework 7.0.6!spring-doc.cadn.net.cn

REST 客户端

Spring 框架提供了以下几种调用 REST 端点的方式:spring-doc.cadn.net.cn

WebClient

WebClient 是一个用于执行 HTTP 请求的非阻塞、响应式客户端。它在 5.0 版本中引入,为 RestTemplate 提供了替代方案,支持同步、异步和流式场景。spring-doc.cadn.net.cn

WebClient 支持以下内容:spring-doc.cadn.net.cn

请参阅 WebClient 了解更多信息。spring-doc.cadn.net.cn

RestTemplate

RestTemplate 在HTTP客户端库之上提供了更高级的API。它使得在一行代码中调用REST端点变得非常简单。它公开了以下几组重载方法:spring-doc.cadn.net.cn

RestTemplate 处于维护模式,仅接受针对微小更改和错误的请求。请考虑改用 WebClient
表1. RestTemplate 方法
方法组 描述

getForObjectspring-doc.cadn.net.cn

通过 GET 方法获取表示。spring-doc.cadn.net.cn

getForEntityspring-doc.cadn.net.cn

通过使用GET方法获取一个<code>0</code>(即状态、标题和正文)。spring-doc.cadn.net.cn

headForHeadersspring-doc.cadn.net.cn

通过 HEAD 方法检索资源的所有标头。spring-doc.cadn.net.cn

postForLocationspring-doc.cadn.net.cn

通过使用 POST 创建新资源,并从响应中返回 Location 头信息。spring-doc.cadn.net.cn

postForObjectspring-doc.cadn.net.cn

通过使用 POST 创建一个新资源,并从响应中返回表示。spring-doc.cadn.net.cn

postForEntityspring-doc.cadn.net.cn

通过使用 POST 创建一个新资源,并从响应中返回表示。spring-doc.cadn.net.cn

putspring-doc.cadn.net.cn

通过 PUT 方法创建或更新资源。spring-doc.cadn.net.cn

patchForObjectspring-doc.cadn.net.cn

通过使用 PATCH 更新资源并从响应中返回表示。 请注意,JDK HttpURLConnection 不支持 PATCH,但 Apache HttpComponents 等其他组件支持。spring-doc.cadn.net.cn

deletespring-doc.cadn.net.cn

通过使用DELETE方法删除指定URI处的资源。spring-doc.cadn.net.cn

optionsForAllowspring-doc.cadn.net.cn

通过使用 ALLOW 来获取资源允许的 HTTP 方法。spring-doc.cadn.net.cn

exchangespring-doc.cadn.net.cn

前面方法的更通用(且更不具倾向性)版本,在需要时提供额外的灵活性。它接受一个 RequestEntity(包括HTTP方法、URL、头信息和正文作为输入),并返回一个 ResponseEntityspring-doc.cadn.net.cn

这些方法允许使用 ParameterizedTypeReference 而不是 Class 来指定带有泛型的响应类型。spring-doc.cadn.net.cn

executespring-doc.cadn.net.cn

执行请求的最通用方式,通过回调接口对请求准备和响应提取进行完全控制。spring-doc.cadn.net.cn

初始化

默认构造函数使用 java.net.HttpURLConnection 来执行请求。您可以 切换到具有 ClientHttpRequestFactory 实现的其他 HTTP 库。 目前,还内置支持 Apache HttpComponents 和 OkHttp。spring-doc.cadn.net.cn

例如,要切换到 Apache HttpComponents,可以使用以下方式:spring-doc.cadn.net.cn

RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory());

每个 ClientHttpRequestFactory 都提供了特定于底层 HTTP 客户端库的配置选项 — 例如,用于凭据、连接池和其他细节。spring-doc.cadn.net.cn

注意,HTTP 请求的 java.net 实现在访问表示错误(如 401)的响应状态时可能会抛出异常。如果这是个问题,请改用其他 HTTP 客户端库。
RestTemplate 可以被用于可观测性,以生成指标和跟踪信息。 请参阅 RestTemplate 可观测性支持 部分。

统一资源标识符

许多 RestTemplate 方法接受一个 URI 模板和 URI 模板变量, 可以作为 String 可变参数,或者作为 Map<String,String>spring-doc.cadn.net.cn

以下示例使用了一个 String 可变参数:spring-doc.cadn.net.cn

String result = restTemplate.getForObject(
		"https://example.com/hotels/{hotel}/bookings/{booking}", String.class, "42", "21");

以下示例使用了 Map<String, String>spring-doc.cadn.net.cn

Map<String, String> vars = Collections.singletonMap("hotel", "42");

String result = restTemplate.getForObject(
		"https://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars);

请记住URI模板会自动进行编码,如下例所示:spring-doc.cadn.net.cn

restTemplate.getForObject("https://example.com/hotel list", String.class);

// Results in request to "https://example.com/hotel%20list"

您可以使用 uriTemplateHandlerRestTemplate 属性来自定义 URIs 的编码方式。或者,您可以准备一个 java.net.URI 并将其传递到接受 URI 的其中一个 RestTemplate 方法中。spring-doc.cadn.net.cn

有关使用和编码URI的更多详细信息,请参阅 URI链接spring-doc.cadn.net.cn

标题

您可以使用 exchange() 方法来指定请求头,如下例所示:spring-doc.cadn.net.cn

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();

您可以通过许多返回RestTemplateResponseEntity方法变体获取响应头。spring-doc.cadn.net.cn

正文

通过 RestTemplate 方法传入和返回的对象会借助 HttpMessageConverter 在原始内容之间进行转换。spring-doc.cadn.net.cn

在 POST 请求中,输入对象会序列化到请求体中,如下例所示:spring-doc.cadn.net.cn

URI location = template.postForLocation("https://example.com/people", person);

您不需要显式设置请求的Content-Type标头。在大多数情况下,可以根据源Object类型找到兼容的消息转换器,并且所选的消息转换器会相应地设置内容类型。如有必要,可以使用exchange方法显式提供Content-Type请求标头,这反过来会影响选择哪个消息转换器。spring-doc.cadn.net.cn

在GET请求中,响应体被反序列化为输出Object,如下例所示:spring-doc.cadn.net.cn

Person person = restTemplate.getForObject("https://example.com/people/{id}", Person.class, 42);

请求的 Accept 头不需要显式设置。在大多数情况下,可以根据预期的响应类型找到兼容的消息转换器,这有助于填充 Accept 头。如有必要,可以使用 exchange 方法显式提供 Accept 头。spring-doc.cadn.net.cn

默认情况下,RestTemplate 注册所有内置的 消息转换器,根据类路径检查来确定哪些可选的转换库存在。您也可以显式设置要使用的消息 转换器。spring-doc.cadn.net.cn

消息转换

spring-web 模块包含通过 InputStreamOutputStream 读取和写入 HTTP 请求和响应正文的 HttpMessageConverter 接口。 HttpMessageConverter 实例在客户端(例如,在 RestTemplate 中)和服务器端(例如,在 Spring MVC REST 控制器中)使用。spring-doc.cadn.net.cn

框架中提供了主要媒体(MIME)类型的具体实现,并且默认情况下在客户端注册为RestTemplate,在服务器端注册为RequestMappingHandlerAdapter(参见 配置消息转换器)。spring-doc.cadn.net.cn

HttpMessageConverter 的实现方法在以下章节中进行了描述。 对于所有转换器,都会使用默认的媒体类型,但您可以通过设置 supportedMediaTypes bean 属性来覆盖它。下表描述了每种实现:spring-doc.cadn.net.cn

表2. HttpMessageConverter 实现类
MessageConverter 描述

StringHttpMessageConverterspring-doc.cadn.net.cn

一个可以从HTTP请求和响应中读取和写入String实例的HttpMessageConverter实现。默认情况下,此转换器支持所有文本媒体类型(text/*),并使用Content-Typetext/plain进行编写。spring-doc.cadn.net.cn

FormHttpMessageConverterspring-doc.cadn.net.cn

一个可以从HTTP请求和响应中读取和写入表单数据的HttpMessageConverter实现。默认情况下,此转换器读取和写入application/x-www-form-urlencoded媒体类型。表单数据从MultiValueMap<String, String>中读取并写入其中。该转换器还可以写入(但不能读取)从MultiValueMap<String, Object>中读取的多部分数据。默认情况下,支持multipart/form-data。从Spring Framework 5.2开始,可以支持额外的多部分子类型来写入表单数据。有关更多详细信息,请参阅FormHttpMessageConverter的javadoc。spring-doc.cadn.net.cn

ByteArrayHttpMessageConverterspring-doc.cadn.net.cn

一个可以从HTTP请求和响应中读取和写入字节数组的HttpMessageConverter实现。默认情况下,此转换器支持所有媒体类型(*/*),并使用Content-Typeapplication/octet-stream进行写入。您可以通过设置supportedMediaTypes属性并重写getContentType(byte[])来覆盖此设置。spring-doc.cadn.net.cn

MarshallingHttpMessageConverterspring-doc.cadn.net.cn

一个 HttpMessageConverter 实现,可以通过 Spring 的 MarshallerUnmarshaller 抽象从 org.springframework.oxm 包中读取和写入 XML。 此转换器在使用前需要 MarshallerUnmarshaller。您可以通过构造函数或 bean 属性注入这些内容。默认情况下,此转换器支持 text/xmlapplication/xmlspring-doc.cadn.net.cn

MappingJackson2HttpMessageConverterspring-doc.cadn.net.cn

一个可以使用 Jackson 的 HttpMessageConverter 读写 JSON 的实现。您可以根据需要通过使用 Jackson 提供的注解来自定义 JSON 映射。当您需要进一步控制(例如需要为特定类型提供自定义的 JSON 序列化器/反序列化器时),可以通过 ObjectMapper 属性注入自定义的 ObjectMapper。默认情况下,此转换器支持 application/jsonspring-doc.cadn.net.cn

MappingJackson2XmlHttpMessageConverterspring-doc.cadn.net.cn

一个可以使用Jackson XML扩展的HttpMessageConverter实现,用于通过XmlMapper读取和写入XML。您可以根据需要通过JAXB或Jackson提供的注释自定义XML映射。当您需要进一步控制(例如需要为特定类型提供自定义XML序列化/反序列化器时),可以通过ObjectMapper属性注入自定义的XmlMapper。默认情况下,此转换器支持application/xmlspring-doc.cadn.net.cn

SourceHttpMessageConverterspring-doc.cadn.net.cn

一个可以读取和写入HTTP请求和响应中HttpMessageConverter的实现。仅支持DOMSourceSAXSourceStreamSource。默认情况下,此转换器支持text/xmlapplication/xmlspring-doc.cadn.net.cn

BufferedImageHttpMessageConverterspring-doc.cadn.net.cn

一个可以读取和写入HTTP请求和响应中的HttpMessageConverter的实现。此转换器读取和写入Java I/O API支持的媒体类型。spring-doc.cadn.net.cn

Jackson JSON 视图

您可以指定一个 Jackson JSON 视图 以仅序列化对象属性的子集,如下例所示:spring-doc.cadn.net.cn

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);

多部分

要发送多部分数据,您需要提供一个 MultiValueMap<String, Object>,其值可以是 Object(用于部分内容)、Resource(用于文件部分)或 HttpEntity(用于带标题的部分内容)。例如:spring-doc.cadn.net.cn

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));

在大多数情况下,您不需要为每个部分指定Content-Type。内容类型是根据用于序列化的HttpMessageConverter自动确定的,或者在基于Resource的情况下,根据文件扩展名确定。如需指定,可以使用MediaType并用HttpEntity包装器显式提供。spring-doc.cadn.net.cn

一旦 MultiValueMap 准备好,您可以将其传递给 RestTemplate,如下所示:spring-doc.cadn.net.cn

MultiValueMap<String, Object> parts = ...;
template.postForObject("https://example.com/upload", parts, Void.class);

如果 MultiValueMap 包含至少一个非 String 的值,则由 FormHttpMessageConverterContent-Type 设置为 multipart/form-data。如果 MultiValueMapString 个值,则 Content-Type 默认设置为 application/x-www-form-urlencoded。 如有需要,也可以显式设置 Content-Typespring-doc.cadn.net.cn

HTTP接口

Spring 框架允许你将 HTTP 服务定义为一个 Java 接口,该接口的方法通过注解来描述 HTTP 交互。然后你可以生成一个实现此接口并执行这些交互的代理。这有助于简化 HTTP 远程访问,通常涉及一个外观模式(facade)来封装使用底层 HTTP 客户端的细节。spring-doc.cadn.net.cn

首先,声明一个包含 @HttpExchange 个方法的接口:spring-doc.cadn.net.cn

interface RepositoryService {

	@GetExchange("/repos/{owner}/{repo}")
	Repository getRepository(@PathVariable String owner, @PathVariable String repo);

	// more HTTP exchange methods...

}

二、创建一个执行已声明的HTTP交换的代理:spring-doc.cadn.net.cn

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 在类型级别受支持,适用于所有方法:spring-doc.cadn.net.cn

@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 交换方法支持灵活的方法签名,可包含以下方法参数:spring-doc.cadn.net.cn

方法参数 描述

URIspring-doc.cadn.net.cn

动态设置请求的URL,覆盖注解的 url 属性。spring-doc.cadn.net.cn

HttpMethodspring-doc.cadn.net.cn

动态设置请求的HTTP方法,覆盖注解的 method 属性spring-doc.cadn.net.cn

@RequestHeaderspring-doc.cadn.net.cn

添加一个请求头或多个请求头。参数可以是带有多个头的 Map<String, ?>MultiValueMap<String, ?>Collection<?> 个值,或单个值。支持非字符串值的类型转换。spring-doc.cadn.net.cn

@PathVariablespring-doc.cadn.net.cn

添加一个变量以在请求URL中展开占位符。该参数可以是多个变量时的Map<String, ?>,也可以是单个值。支持非字符串值的类型转换。spring-doc.cadn.net.cn

@RequestBodyspring-doc.cadn.net.cn

将请求的正文提供为要序列化的对象,或作为响应式流 Publisher(例如 MonoFlux),或通过配置的 ReactiveAdapterRegistry 支持的任何其他异步类型。spring-doc.cadn.net.cn

@RequestParamspring-doc.cadn.net.cn

添加一个请求参数或多个参数。该参数可以是多个参数的 Map<String, ?>MultiValueMap<String, ?>,值的 Collection<?>,或单个值。支持非字符串值的类型转换。spring-doc.cadn.net.cn

当将 "content-type" 设置为 "application/x-www-form-urlencoded" 时,请求参数会被编码到请求正文中。否则,它们将作为URL查询参数添加。spring-doc.cadn.net.cn

@RequestPartspring-doc.cadn.net.cn

添加一个请求部分,该部分可以是字符串(表单字段)、Resource(文件部分)、 对象(要编码的实体,例如 JSON)、HttpEntity(部分内容和头部信息)、 Spring Part 或上述任意类型的响应式流 Publisherspring-doc.cadn.net.cn

@CookieValuespring-doc.cadn.net.cn

添加一个或多个cookie。该参数可以是多个cookie的 Map<String, ?>MultiValueMap<String, ?>,一组值的 Collection<?>,或单个值。支持非字符串值的类型转换。spring-doc.cadn.net.cn

返回值

使用注解的 HTTP 交换方法支持以下返回值:spring-doc.cadn.net.cn

方法返回值 描述

void, Mono<Void>spring-doc.cadn.net.cn

执行给定的请求,并释放响应内容(如果有)。spring-doc.cadn.net.cn

HttpHeaders, Mono<HttpHeaders>spring-doc.cadn.net.cn

执行给定的请求,释放响应内容(如果有),并返回响应头。spring-doc.cadn.net.cn

<T>, Mono<T>spring-doc.cadn.net.cn

执行给定的请求,并将响应内容解码为声明的返回类型。spring-doc.cadn.net.cn

<T>, Flux<T>spring-doc.cadn.net.cn

执行给定的请求,并将响应内容解码为声明的元素类型的流。spring-doc.cadn.net.cn

ResponseEntity<Void>, Mono<ResponseEntity<Void>>spring-doc.cadn.net.cn

执行给定的请求,并释放响应内容(如果有),然后返回一个包含状态和头部信息的 ResponseEntityspring-doc.cadn.net.cn

ResponseEntity<T>, Mono<ResponseEntity<T>>spring-doc.cadn.net.cn

执行给定的请求,将响应内容解码为声明的返回类型,并返回一个包含状态、头部和解码后主体的 ResponseEntityspring-doc.cadn.net.cn

Mono<ResponseEntity<Flux<T>>spring-doc.cadn.net.cn

执行给定的请求,将响应内容解码为声明的元素类型的流,并返回一个包含状态、头部和解码后的响应体流的ResponseEntityspring-doc.cadn.net.cn

您也可以使用在 ReactiveAdapterRegistry 中注册的任何其他异步或响应式类型。

异常处理

默认情况下,WebClient 会对 4xx 和 5xx HTTP 状态码返回 WebClientResponseException。要自定义此行为,可以注册一个响应状态处理器,该处理器将应用于通过客户端执行的所有响应:spring-doc.cadn.net.cn

WebClient webClient = WebClient.builder()
		.defaultStatusHandler(HttpStatusCode::isError, resp -> ...)
		.build();

WebClientAdapter clientAdapter = WebClientAdapter.forClient(webClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory
		.builder(clientAdapter).build();

有关更多详细信息和选项(例如抑制错误状态码),请参阅 WebClient.BuilderdefaultStatusHandler 的 Javadoc。spring-doc.cadn.net.cn