Spring Framework 提供了以下用于调用 REST 端点的选择:

  • RestClient - 具有流畅 API 的同步客户端。

  • WebClient - 具有流畅 API 的非阻塞、反应式客户端.

  • RestTemplate - 具有模板方法 API 的同步客户端。

  • HTTP 接口 - 带有生成的动态代理实现的带注释的接口。

RestClient

这是一个同步 HTTP 客户端,提供现代、流畅的 API。 它提供了对 HTTP 库的抽象,允许方便地将 Java 对象转换为 HTTP 请求,以及从 HTTP 响应创建对象。RestClient

创建RestClient

是使用静态方法之一创建的。 您还可以使用来获取具有更多选项的构建器,例如指定要使用的 HTTP 库(请参阅客户端请求工厂)和要使用的消息转换器(请参阅 HTTP 消息转换)、设置默认 URI、默认路径变量、默认请求标头或 ,或注册侦听器和初始值设定项。RestClientcreatebuilder()uriBuilderFactory

一旦创建(或构建),就可以由多个线程安全地使用。RestClient

下面的示例演示如何创建默认值,以及如何生成自定义值。RestClient

  • Java

  • Kotlin

RestClient defaultClient = RestClient.create();

RestClient customClient = RestClient.builder()
  .requestFactory(new HttpComponentsClientHttpRequestFactory())
  .messageConverters(converters -> converters.add(new MyCustomMessageConverter()))
  .baseUrl("https://example.com")
  .defaultUriVariables(Map.of("variable", "foo"))
  .defaultHeader("My-Header", "Foo")
  .requestInterceptor(myCustomInterceptor)
  .requestInitializer(myCustomInitializer)
  .build();
val defaultClient = RestClient.create()

val customClient = RestClient.builder()
  .requestFactory(HttpComponentsClientHttpRequestFactory())
  .messageConverters { converters -> converters.add(MyCustomMessageConverter()) }
  .baseUrl("https://example.com")
  .defaultUriVariables(mapOf("variable" to "foo"))
  .defaultHeader("My-Header", "Foo")
  .requestInterceptor(myCustomInterceptor)
  .requestInitializer(myCustomInitializer)
  .build()

使用RestClient

使用 发出 HTTP 请求时,首先要指定的是要使用的 HTTP 方法。 这可以使用方便方法、、等来完成。RestClientmethod(HttpMethod)get()head()post()

请求 URL

接下来,可以使用以下方法指定请求 URI。 此步骤是可选的,如果配置了默认 URI,则可以跳过此步骤。 URL 通常指定为 ,带有可选的 URI 模板变量。 以下示例将 GET 请求配置为:uriRestClientStringexample.com/orders/42

  • Java

  • Kotlin

int id = 42;
restClient.get()
  .uri("https://example.com/orders/{id}", id)
  ....
val id = 42
restClient.get()
  .uri("https://example.com/orders/{id}", id)
  ...

函数还可用于更多控件,例如指定请求参数

默认情况下,字符串 URL 是编码的,但这可以通过使用自定义 . URL 也可以与函数一起提供,也可以作为 提供,这两者都不编码。 有关使用 URI 和编码 URI 的更多详细信息,请参阅 URI 链接uriBuilderFactoryjava.net.URI

请求标头和正文

如有必要,可以通过添加带有 、 或方便方法的请求标头来操作 HTTP 请求,依此类推。 对于可以包含正文 (、 和 ) 的 HTTP 请求,可以使用其他方法:和 。header(String, String)headers(Consumer<HttpHeaders>accept(MediaType…​)acceptCharset(Charset…​)POSTPUTPATCHcontentType(MediaType)contentLength(long)

请求正文本身可以由 设置,后者内部使用 HTTP 消息转换。 或者,可以使用 来设置请求正文,从而允许您使用泛型。 最后,可以将 body 设置为写入 .body(Object)ParameterizedTypeReferenceOutputStream

检索响应

设置请求后,将通过调用 来访问 HTTP 响应。 可以使用或针对参数化类型(如列表)访问响应正文。 该方法将响应内容转换为各种类型,例如,字节可以转换为 ,JSON 可以使用 Jackson 转换为对象,等等(参见 HTTP 消息转换)。retrieve()body(Class)body(ParameterizedTypeReference)bodyString

响应也可以转换为 ,从而可以访问响应标头和正文。ResponseEntity

此示例演示如何使用它来执行简单的请求。RestClientGET

  • Java

  • Kotlin

String result = restClient.get() (1)
  .uri("https://example.com") (2)
  .retrieve() (3)
  .body(String.class); (4)

System.out.println(result); (5)
1 设置 GET 请求
2 指定要连接到的 URL
3 检索响应
4 将响应转换为字符串
5 打印结果
val result= restClient.get() (1)
  .uri("https://example.com") (2)
  .retrieve() (3)
  .body<String>() (4)

println(result) (5)
1 设置 GET 请求
2 指定要连接到的 URL
3 检索响应
4 将响应转换为字符串
5 打印结果

通过以下方式提供对响应状态代码和标头的访问:ResponseEntity

  • Java

  • Kotlin

ResponseEntity<String> result = restClient.get() (1)
  .uri("https://example.com") (1)
  .retrieve()
  .toEntity(String.class); (2)

System.out.println("Response status: " + result.getStatusCode()); (3)
System.out.println("Response headers: " + result.getHeaders()); (3)
System.out.println("Contents: " + result.getBody()); (3)
1 为指定的 URL 设置 GET 请求
2 将响应转换为ResponseEntity
3 打印结果
val result = restClient.get() (1)
  .uri("https://example.com") (1)
  .retrieve()
  .toEntity<String>() (2)

println("Response status: " + result.statusCode) (3)
println("Response headers: " + result.headers) (3)
println("Contents: " + result.body) (3)
1 为指定的 URL 设置 GET 请求
2 将响应转换为ResponseEntity
3 打印结果

RestClient可以使用 Jackson 库将 JSON 转换为对象。 请注意此示例中 URI 变量的用法,并且标头设置为 JSON。Accept

  • Java

  • Kotlin

int id = ...;
Pet pet = restClient.get()
  .uri("https://petclinic.example.com/pets/{id}", id) (1)
  .accept(APPLICATION_JSON) (2)
  .retrieve()
  .body(Pet.class); (3)
1 使用 URI 变量
2 将标头设置为Acceptapplication/json
3 将 JSON 响应转换为域对象Pet
val id = ...
val pet = restClient.get()
  .uri("https://petclinic.example.com/pets/{id}", id) (1)
  .accept(APPLICATION_JSON) (2)
  .retrieve()
  .body<Pet>() (3)
1 使用 URI 变量
2 将标头设置为Acceptapplication/json
3 将 JSON 响应转换为域对象Pet

在下一个示例中,用于执行包含 JSON 的 POST 请求,该请求再次使用 Jackson 进行转换。RestClient

  • Java

  • Kotlin

Pet pet = ... (1)
ResponseEntity<Void> response = restClient.post() (2)
  .uri("https://petclinic.example.com/pets/new") (2)
  .contentType(APPLICATION_JSON) (3)
  .body(pet) (4)
  .retrieve()
  .toBodilessEntity(); (5)
1 创建域对象Pet
2 设置 POST 请求和要连接到的 URL
3 将标头设置为Content-Typeapplication/json
4 用作请求正文pet
5 将响应转换为没有正文的响应实体。
val pet: Pet = ... (1)
val response = restClient.post() (2)
  .uri("https://petclinic.example.com/pets/new") (2)
  .contentType(APPLICATION_JSON) (3)
  .body(pet) (4)
  .retrieve()
  .toBodilessEntity() (5)
1 创建域对象Pet
2 设置 POST 请求和要连接到的 URL
3 将标头设置为Content-Typeapplication/json
4 用作请求正文pet
5 将响应转换为没有正文的响应实体。

错误处理

默认情况下,在检索具有 4xx 或 5xx 状态代码的响应时抛出 的子类。 可以使用 来覆盖此行为。RestClientRestClientExceptiononStatus

  • Java

  • Kotlin

String result = restClient.get() (1)
  .uri("https://example.com/this-url-does-not-exist") (1)
  .retrieve()
  .onStatus(HttpStatusCode::is4xxClientError, (request, response) -> { (2)
      throw new MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()) (3)
  })
  .body(String.class);
1 为返回 404 状态代码的 URL 创建 GET 请求
2 为所有 4xx 状态代码设置状态处理程序
3 引发自定义异常
val result = restClient.get() (1)
  .uri("https://example.com/this-url-does-not-exist") (1)
  .retrieve()
  .onStatus(HttpStatusCode::is4xxClientError) { _, response -> (2)
    throw MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()) } (3)
  .body<String>()
1 为返回 404 状态代码的 URL 创建 GET 请求
2 为所有 4xx 状态代码设置状态处理程序
3 引发自定义异常

交换

对于更高级的方案,可以通过该方法访问基础 HTTP 请求和响应,该方法可以代替 . 使用时不应用状态处理程序,因为 exchange 函数已经提供了对完整响应的访问,允许您执行任何必要的错误处理。RestClientexchange()retrieve()exchange()

  • Java

  • Kotlin

Pet result = restClient.get()
  .uri("https://petclinic.example.com/pets/{id}", id)
  .accept(APPLICATION_JSON)
  .exchange((request, response) -> { (1)
    if (response.getStatusCode().is4xxClientError()) { (2)
      throw new MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()); (2)
    }
    else {
      Pet pet = convertResponse(response); (3)
      return pet;
    }
  });
1 exchange提供请求和响应
2 当响应具有 4xx 状态代码时引发异常
3 将响应转换为 Pet 域对象
val result = restClient.get()
  .uri("https://petclinic.example.com/pets/{id}", id)
  .accept(MediaType.APPLICATION_JSON)
  .exchange { request, response -> (1)
    if (response.getStatusCode().is4xxClientError()) { (2)
      throw MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()) (2)
    } else {
      val pet: Pet = convertResponse(response) (3)
      pet
    }
  }
1 exchange提供请求和响应
2 当响应具有 4xx 状态代码时引发异常
3 将响应转换为 Pet 域对象

HTTP 消息转换

该模块包含用于读取和写入 HTTP 请求和响应正文的接口。 实例用于客户端(例如,在 )和服务器端(例如,在 Spring MVC REST 控制器中)。spring-webHttpMessageConverterInputStreamOutputStreamHttpMessageConverterRestClient

框架中提供了主媒体 (MIME) 类型的具体实现,默认情况下,在客户端和 和 以及服务器端注册(请参阅配置消息转换器)。RestClientRestTemplateRequestMappingHandlerAdapter

下面介绍了几种实现。 有关完整列表,请参阅 HttpMessageConverter Javadoc。 对于所有转换器,都使用默认媒体类型,但您可以通过设置属性来覆盖它。HttpMessageConvertersupportedMediaTypes

表 1.HttpMessageConverter 实现
消息转换器 描述

StringHttpMessageConverter

可以从 HTTP 请求和响应读取和写入实例的实现。 默认情况下,此转换器支持所有文本媒体类型(),并使用 的 写入。HttpMessageConverterStringtext/*Content-Typetext/plain

FormHttpMessageConverter

可以从 HTTP 请求和响应读取和写入表单数据的实现。 默认情况下,此转换器读取和写入媒体类型。 表单数据从 . 转换器还可以写入(但不能读取)从 . 默认情况下,受支持。 可以支持其他多部分子类型来写入表单数据。 有关更多详细信息,请参阅 javadoc。HttpMessageConverterapplication/x-www-form-urlencodedMultiValueMap<String, String>MultiValueMap<String, Object>multipart/form-dataFormHttpMessageConverter

ByteArrayHttpMessageConverter

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

MarshallingHttpMessageConverter

一个可以通过使用 Spring 和包中的抽象来读取和写入 XML 的实现。 此转换器在使用之前需要 and。 您可以通过构造函数或 Bean 属性注入这些属性。 默认情况下,此转换器支持 和 。HttpMessageConverterMarshallerUnmarshallerorg.springframework.oxmMarshallerUnmarshallertext/xmlapplication/xml

MappingJackson2HttpMessageConverter

可以使用 Jackson 的 . 您可以通过使用 Jackson 提供的注释根据需要自定义 JSON 映射。 当需要进一步控制时(对于需要为特定类型提供自定义 JSON 序列化程序/反序列化程序的情况),可以通过该属性注入自定义项。 默认情况下,此转换器支持 .HttpMessageConverterObjectMapperObjectMapperObjectMapperapplication/json

MappingJackson2XmlHttpMessageConverter

可以使用 Jackson XML 扩展的 . 您可以根据需要使用 JAXB 或 Jackson 提供的注释来自定义 XML 映射。 当需要进一步控制时(对于需要为特定类型提供自定义 XML 序列化程序/反序列化程序的情况),可以通过该属性注入自定义项。 默认情况下,此转换器支持 .HttpMessageConverterXmlMapperXmlMapperObjectMapperapplication/xml

SourceHttpMessageConverter

可以从 HTTP 请求和响应读取和写入的实现。 仅支持 、 和 。 默认情况下,此转换器支持 和 。HttpMessageConverterjavax.xml.transform.SourceDOMSourceSAXSourceStreamSourcetext/xmlapplication/xml

默认情况下,并注册所有内置消息转换器,具体取决于类路径上基础库的可用性。 还可以通过使用生成器上的方法或通过 的属性将消息转换器设置为显式使用 。RestClientRestTemplatemessageConverters()RestClientmessageConvertersRestTemplate

Jackson JSON 视图

若要仅序列化对象属性的子集,可以指定 Jackson JSON 视图,如以下示例所示:

MappingJacksonValue value = new MappingJacksonValue(new User("eric", "7!jd#h23"));
value.setSerializationView(User.WithoutPasswordView.class);

ResponseEntity<Void> response = restClient.post() // or RestTemplate.postForEntity
  .contentType(APPLICATION_JSON)
  .body(value)
  .retrieve()
  .toBodilessEntity();

多部分

若要发送多部分数据,需要提供其值可以是 for 部件内容、文件部件或带有标头的 for 部件内容。 例如:MultiValueMap<String, Object>ObjectResourceHttpEntity

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

// send using RestClient.post or RestTemplate.postForEntity

在大多数情况下,您不必为每个部件指定 。 内容类型是根据所选择的序列化内容自动确定的,或者在序列化的情况下,基于文件扩展名。 如有必要,可以显式提供包装器。Content-TypeHttpMessageConverterResourceMediaTypeHttpEntity

准备就绪后,可以使用(或 )将其用作请求的正文。MultiValueMapPOSTRestClient.post().body(parts)RestTemplate.postForObject

如果 包含至少一个非值,则 设置为 。 如果 有值,则默认为 。 如有必要,也可以显式设置。MultiValueMapStringContent-Typemultipart/form-dataFormHttpMessageConverterMultiValueMapStringContent-Typeapplication/x-www-form-urlencodedContent-Type

客户端请求工厂

若要执行 HTTP 请求,请使用客户端 HTTP 库。 这些库通过界面进行调整。 有多种实现方式可供选择:RestClientClientRequestFactory

  • JdkClientHttpRequestFactory对于 Java 的HttpClient

  • HttpComponentsClientHttpRequestFactory用于 Apache HTTP 组件HttpClient

  • JettyClientHttpRequestFactory对于Jetty'sHttpClient

  • ReactorNettyClientRequestFactory用于 Reactor Netty'sHttpClient

  • SimpleClientHttpRequestFactory作为简单的默认值

如果在构建时未指定请求工厂,它将使用 Apache 或 Jetty(如果它们在类路径上可用)。 否则,如果加载了模块,它将使用 Java 的 . 最后,它将采用简单的默认值。RestClientHttpClientjava.net.httpHttpClient

请注意,在访问表示错误的响应状态(例如 401)时,可能会引发异常。 如果这是一个问题,请使用任何替代请求工厂。SimpleClientHttpRequestFactory

WebClient

WebClient是用于执行 HTTP 请求的非阻塞反应式客户端。它是 在 5.0 中引入,并提供了 的替代方案,支持 同步、异步和流式处理方案。RestTemplate

WebClient支持以下功能:

  • 非阻塞 I/O

  • 反应流背压

  • 硬件资源少,高并发

  • 利用 Java 8 lambda 的功能式流畅 API

  • 同步和异步交互

  • 向上流式传输到服务器或从服务器向式传输

有关详细信息,请参阅 WebClient

RestTemplate

它以经典的 Spring Template 类的形式提供了基于 HTTP 客户端库的高级 API。 它公开了以下重载方法组:RestTemplate

RestClient 为同步 HTTP 访问提供了更现代的 API。 对于异步和流式处理方案,请考虑反应式 WebClient
表 2.RestTemplate 方法
方法组 描述

getForObject

通过 GET 检索表示。

getForEntity

使用 GET 检索 (即 status、headers 和 body)。ResponseEntity

headForHeaders

使用 HEAD 检索资源的所有标头。

postForLocation

使用 POST 创建新资源,并从响应中返回标头。Location

postForObject

使用 POST 创建新资源,并从响应中返回表示形式。

postForEntity

使用 POST 创建新资源,并从响应中返回表示形式。

put

使用 PUT 创建或更新资源。

patchForObject

使用 PATCH 更新资源,并从响应中返回表示形式。 请注意,JDK 不支持 ,但 Apache HttpComponents 和其他支持。HttpURLConnectionPATCH

delete

使用 DELETE 删除指定 URI 处的资源。

optionsForAllow

使用 ALLOW 检索资源允许的 HTTP 方法。

exchange

上述方法的更通用(且不那么固执己见)版本,可在需要时提供额外的灵活性。 它接受 a(包括 HTTP 方法、URL、标头和正文作为输入)并返回 .RequestEntityResponseEntity

这些方法允许使用 而不是指定 具有泛型的响应类型。ParameterizedTypeReferenceClass

execute

执行请求的最通用方式,可完全控制请求 通过回调接口进行准备和响应提取。

初始化

RestTemplate使用与 相同的 HTTP 库抽象。 默认情况下,它使用 ,但这可以通过构造函数进行更改。 请参阅客户端请求工厂RestClientSimpleClientHttpRequestFactory

RestTemplate可以检测可观察性,以生成指标和跟踪。 请参阅 RestTemplate 可观测性支持部分。

身体

传入和从方法返回的对象在 的帮助下与 HTTP 消息之间相互转换,请参见HTTP 消息转换RestTemplateHttpMessageConverter

从 迁移到RestTemplateRestClient

下表显示了方法的等效项。 它可用于从后者迁移到前者。RestClientRestTemplate

表 3.RestTemplate 方法的 RestClient 等效项
RestTemplate方法 RestClient等效

getForObject(String, Class, Object…​)

get() .uri(String, Object…​) .retrieve() .body(Class)

getForObject(String, Class, Map)

get() .uri(String, Map) .retrieve() .body(Class)

getForObject(URI, Class)

get() .uri(URI) .retrieve() .body(Class)

getForEntity(String, Class, Object…​)

get() .uri(String, Object…​) .retrieve() .toEntity(Class)

getForEntity(String, Class, Map)

get() .uri(String, Map) .retrieve() .toEntity(Class)

getForEntity(URI, Class)

get() .uri(URI) .retrieve() .toEntity(Class)

headForHeaders(String, Object…​)

head() .uri(String, Object…​) .retrieve() .toBodilessEntity() .getHeaders()

headForHeaders(String, Map)

head() .uri(String, Map) .retrieve() .toBodilessEntity() .getHeaders()

headForHeaders(URI)

head() .uri(URI) .retrieve() .toBodilessEntity() .getHeaders()

postForLocation(String, Object, Object…​)

post() .uri(String, Object…​) .body(Object).retrieve() .toBodilessEntity() .getLocation()

postForLocation(String, Object, Map)

post() .uri(String, Map) .body(Object) .retrieve() .toBodilessEntity() .getLocation()

postForLocation(URI, Object)

post() .uri(URI) .body(Object) .retrieve() .toBodilessEntity() .getLocation()

postForObject(String, Object, Class, Object…​)

post() .uri(String, Object…​) .body(Object) .retrieve() .body(Class)

postForObject(String, Object, Class, Map)

post() .uri(String, Map) .body(Object) .retrieve() .body(Class)

postForObject(URI, Object, Class)

post() .uri(URI) .body(Object) .retrieve() .body(Class)

postForEntity(String, Object, Class, Object…​)

post() .uri(String, Object…​) .body(Object) .retrieve() .toEntity(Class)

postForEntity(String, Object, Class, Map)

post() .uri(String, Map) .body(Object) .retrieve() .toEntity(Class)

postForEntity(URI, Object, Class)

post() .uri(URI) .body(Object) .retrieve() .toEntity(Class)

put(String, Object, Object…​)

put() .uri(String, Object…​) .body(Object) .retrieve() .toBodilessEntity()

put(String, Object, Map)

put() .uri(String, Map) .body(Object) .retrieve() .toBodilessEntity()

put(URI, Object)

put() .uri(URI) .body(Object) .retrieve() .toBodilessEntity()

patchForObject(String, Object, Class, Object…​)

patch() .uri(String, Object…​) .body(Object) .retrieve() .body(Class)

patchForObject(String, Object, Class, Map)

patch() .uri(String, Map) .body(Object) .retrieve() .body(Class)

patchForObject(URI, Object, Class)

patch() .uri(URI) .body(Object) .retrieve() .body(Class)

delete(String, Object…​)

delete() .uri(String, Object…​) .retrieve() .toBodilessEntity()

delete(String, Map)

delete() .uri(String, Map) .retrieve() .toBodilessEntity()

delete(URI)

delete() .uri(URI) .retrieve() .toBodilessEntity()

optionsForAllow(String, Object…​)

options() .uri(String, Object…​) .retrieve() .toBodilessEntity() .getAllow()

optionsForAllow(String, Map)

options() .uri(String, Map) .retrieve() .toBodilessEntity() .getAllow()

optionsForAllow(URI)

options() .uri(URI) .retrieve() .toBodilessEntity() .getAllow()

exchange(String, HttpMethod, HttpEntity, Class, Object…​)

method(HttpMethod) .uri(String, Object…​) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(Class) [1]

exchange(String, HttpMethod, HttpEntity, Class, Map)

method(HttpMethod) .uri(String, Map) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(Class) [1]

exchange(URI, HttpMethod, HttpEntity, Class)

method(HttpMethod) .uri(URI) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(Class) [1]

exchange(String, HttpMethod, HttpEntity, ParameterizedTypeReference, Object…​)

method(HttpMethod) .uri(String, Object…​) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(ParameterizedTypeReference) [1]

exchange(String, HttpMethod, HttpEntity, ParameterizedTypeReference, Map)

method(HttpMethod) .uri(String, Map) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(ParameterizedTypeReference) [1]

exchange(URI, HttpMethod, HttpEntity, ParameterizedTypeReference)

method(HttpMethod) .uri(URI) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(ParameterizedTypeReference) [1]

exchange(RequestEntity, Class)

method(HttpMethod) .uri(URI) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(Class) [2]

exchange(RequestEntity, ParameterizedTypeReference)

method(HttpMethod) .uri(URI) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(ParameterizedTypeReference) [2]

execute(String, HttpMethod, RequestCallback, ResponseExtractor, Object…​)

method(HttpMethod) .uri(String, Object…​) .exchange(ExchangeFunction)

execute(String, HttpMethod, RequestCallback, ResponseExtractor, Map)

method(HttpMethod) .uri(String, Map) .exchange(ExchangeFunction)

execute(URI, HttpMethod, RequestCallback, ResponseExtractor)

method(HttpMethod) .uri(URI) .exchange(ExchangeFunction)

HTTP 接口

Spring Framework 允许您将 HTTP 服务定义为带有方法的 Java 接口。您可以将此类接口传递给 以创建一个代理,该代理通过 HTTP 客户端(如 或 )执行请求。您还可以从 for 服务器实现接口 请求处理。@HttpExchangeHttpServiceProxyFactoryRestClientWebClient@Controller

首先使用以下方法创建接口:@HttpExchange

interface RepositoryService {

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

	// more HTTP exchange methods...

}

现在,您可以创建一个代理,用于在调用方法时执行请求。

为:RestClient

RestClient restClient = RestClient.builder().baseUrl("https://api.github.com/").build();
RestClientAdapter adapter = RestClientAdapter.create(restClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();

RepositoryService service = factory.createClient(RepositoryService.class);

为:WebClient

WebClient webClient = WebClient.builder().baseUrl("https://api.github.com/").build();
WebClientAdapter adapter = WebClientAdapter.create(webClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();

RepositoryService service = factory.createClient(RepositoryService.class);

为:RestTemplate

RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory("https://api.github.com/"));
RestTemplateAdapter adapter = RestTemplateAdapter.create(restTemplate);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).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 交换方法支持灵活的方法签名,具有以下功能 方法参数:

方法参数 描述

URI

动态设置请求的 URL,覆盖注释的属性。url

UriBuilderFactory

提供用于扩展 URI 模板和 URI 变量的 WITH。 实际上,替换基础客户端的 (及其基本 URL)。UriBuilderFactoryUriBuilderFactory

HttpMethod

动态设置请求的 HTTP 方法,覆盖注释的属性method

@RequestHeader

添加一个或多个请求标头。参数可以是具有多个标头的 或、值的 或 个人价值。非 String 值支持类型转换。Map<String, ?>MultiValueMap<String, ?>Collection<?>

@PathVariable

添加一个变量,以便在请求 URL 中展开占位符。参数可以是具有多个变量的 a,也可以是单个值。类型转换 支持非 String 值。Map<String, ?>

@RequestAttribute

提供要添加为请求的属性。仅受 支持。ObjectWebClient

@RequestBody

提供请求的正文作为要序列化的对象,或 支持的反应式流(如 、 或任何其他异步类型) 通过配置的 .PublisherMonoFluxReactiveAdapterRegistry

@RequestParam

添加一个或多个请求参数。参数可以是具有多个参数的 a、值的 a 或 单个值。非 String 值支持类型转换。Map<String, ?>MultiValueMap<String, ?>Collection<?>

当设置为 时,请求 参数在请求正文中编码。否则,它们将添加为 URL 查询 参数。"content-type""application/x-www-form-urlencoded"

@RequestPart

添加请求部分,可以是 String(表单字段)、(文件部分)、 对象(要编码的实体,例如 JSON)、(部分内容和标头)、 弹簧,或上述任何一种的反应流。ResourceHttpEntityPartPublisher

MultipartFile

添加请求部分,通常用于 Spring MVC 控制器 其中它表示上传的文件。MultipartFile

@CookieValue

添加一个或多个 Cookie。参数可以是具有多个 cookie 的 或、值的 或 个人价值。非 String 值支持类型转换。Map<String, ?>MultiValueMap<String, ?>Collection<?>

返回值

支持的返回值取决于基础客户端。

适用于并支持同步返回值的客户端:HttpExchangeAdapterRestClientRestTemplate

方法返回值 描述

void

执行给定的请求。

HttpHeaders

执行给定的请求并返回响应标头。

<T>

执行给定的请求,并将响应内容解码为声明的返回类型。

ResponseEntity<Void>

执行给定的请求并返回带有状态和标头的 a。ResponseEntity

ResponseEntity<T>

执行给定的请求,将响应内容解码为声明的返回类型,然后 返回 A 以及状态、标头和解码正文。ResponseEntity

客户端适应如,支持以上所有 以及反应性变体。下表显示了反应器类型,但您也可以使用 通过以下方式支持的其他反应式类型:ReactorHttpExchangeAdapterWebClientReactiveAdapterRegistry

方法返回值 描述

Mono<Void>

执行给定的请求,并发布响应内容(如果有)。

Mono<HttpHeaders>

执行给定的请求,释放响应内容(如果有),然后返回 响应标头。

Mono<T>

执行给定的请求,并将响应内容解码为声明的返回类型。

Flux<T>

执行给定的请求并将响应内容解码为声明的流 元素类型。

Mono<ResponseEntity<Void>>

执行给定的请求,并释放响应内容(如果有),并返回带有状态和标头的 a。ResponseEntity

Mono<ResponseEntity<T>>

执行给定的请求,将响应内容解码为声明的返回类型,然后 返回 A 以及状态、标头和解码正文。ResponseEntity

Mono<ResponseEntity<Flux<T>>

执行给定的请求,将响应内容解码为声明的流 元素类型,并返回 A 与状态、标头和解码 响应正文流。ResponseEntity

默认情况下,同步返回值的超时取决于基础 HTTP 客户端的配置方式。您也可以在适配器级别上设置一个值,但我们建议依赖 底层 HTTP 客户端,它在较低级别运行并提供更多控制。ReactorHttpExchangeAdapterblockTimeout

错误处理

要自定义错误响应处理,您需要配置基础 HTTP 客户端。

为:RestClient

默认情况下,引发 4xx 和 5xx HTTP 状态代码。 若要自定义此项,请注册适用于所有响应的响应状态处理程序 通过客户端执行:RestClientRestClientException

RestClient restClient = RestClient.builder()
		.defaultStatusHandler(HttpStatusCode::isError, (request, response) -> ...)
		.build();

RestClientAdapter adapter = RestClientAdapter.create(restClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();

有关更多详细信息和选项,例如禁止显示错误状态代码,请参阅 in 的 Javadoc。defaultStatusHandlerRestClient.Builder

为:WebClient

默认情况下,引发 4xx 和 5xx HTTP 状态代码。 若要自定义此项,请注册适用于所有响应的响应状态处理程序 通过客户端执行:WebClientWebClientResponseException

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

WebClientAdapter adapter = WebClientAdapter.create(webClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(adapter).build();

有关更多详细信息和选项,例如禁止显示错误状态代码,请参阅 in 的 Javadoc。defaultStatusHandlerWebClient.Builder

为:RestTemplate

默认情况下,引发 4xx 和 5xx HTTP 状态代码。 若要自定义此项,请注册适用于所有响应的错误处理程序 通过客户端执行:RestTemplateRestClientException

RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(myErrorHandler);

RestTemplateAdapter adapter = RestTemplateAdapter.create(restTemplate);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();

有关更多详细信息和选项,请参阅 in 和 的 Javadoc 层次结构。setErrorHandlerRestTemplateResponseErrorHandler


1. 接头和主体必须提供给 Via 和 .HttpEntityRestClientheaders(Consumer<HttpHeaders>)body(Object)
2. 方法、URI、标头和正文必须提供给 via 、 和 。RequestEntityRestClientmethod(HttpMethod)uri(URI)headers(Consumer<HttpHeaders>)body(Object)