REST Clients

  • RestClient:带流畅 API 的同步客户端。

  • WebClient:带流畅 API 的非阻塞、响应式客户端。

  • RestTemplate:带模板方法 API 的同步客户端。

  • HTTP 接口:带生成、动态代理实现的带注解的接口。

这些方法的核心差异是它们执行请求的方式,包括同步还是异步、阻塞还是非阻塞,以及如何处理响应。

Spring Framework 提供了针对 REST 端点进行调用的以下选择:

The Spring Framework provides the following choices for making calls to REST endpoints:

  • RestClient - synchronous client with a fluent API.

  • WebClient - non-blocking, reactive client with fluent API.

  • RestTemplate - synchronous client with template method API.

  • HTTP Interface - annotated interface with generated, dynamic proxy implementation.

RestClient

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

The RestClient is a synchronous HTTP client that offers a modern, fluent API. It offers an abstraction over HTTP libraries that allows for convenient conversion from a Java object to an HTTP request, and the creation of objects from an HTTP response.

Creating a RestClient

RestClient 使用静态 create 方法之一创建。您还可以使用 builder() 获取具有更多选项的构建器,例如指定要使用哪个 HTTP 库(参见 Client Request Factories)和要使用哪个消息转换器(参见 HTTP Message Conversion),设置默认 URI、默认路径变量、默认请求头或 uriBuilderFactory,或者注册拦截器和初始化器。

The RestClient is created using one of the static create methods. You can also use builder() to get a builder with further options, such as specifying which HTTP library to use (see Client Request Factories) and which message converters to use (see HTTP Message Conversion), setting a default URI, default path variables, default request headers, or uriBuilderFactory, or registering interceptors and initializers.

创建(或构建)后,RestClient 可以被多个线程安全地使用。

Once created (or built), the RestClient can be used safely by multiple threads.

以下示例演示了如何创建默认 RestClient,以及如何构建自定义 RestClient

The following sample shows how to create a default RestClient, and how to build a custom one.

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

Using the RestClient

在使用 RestClient 发起 HTTP 请求时,首先要指定要使用哪种 HTTP 方法。这可以通过 method(HttpMethod) 或通过便捷方法 get()head()post() 等来完成。

When making an HTTP request with the RestClient, the first thing to specify is which HTTP method to use. This can be done with method(HttpMethod) or with the convenience methods get(), head(), post(), and so on.

Request URL

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

Next, the request URI can be specified with the uri methods. This step is optional and can be skipped if the RestClient is configured with a default URI. The URL is typically specified as a String, with optional URI template variables. The following example configures a GET request to https://example.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)
  ...

函数也可用于更多控件,例如指定 request parameters.

A function can also be used for more controls, such as specifying request parameters.

默认情况下对字符串 URL 进行编码,但可以通过使用自定义 `uriBuilderFactory`来构建客户端来更改此行为。还可以通过函数或作为 `java.net.URI`来提供 URL,两者均不编码。有关处理和编码 URI 的更多详细信息,请参见 URI Links.

String URLs are encoded by default, but this can be changed by building a client with a custom uriBuilderFactory. The URL can also be provided with a function or as a java.net.URI, both of which are not encoded. For more details on working with and encoding URIs, see URI Links.

Request headers and body

如果需要,可以通过使用 header(String,String), headers(Consumer<HttpHeaders), 或使用便捷方法 accept(MediaType…​), acceptCharset(Charset…​) 以及其他方法来添加请求头来操作 HTTP 请求。对于可以包含正文 (POSTPUTPATCH) 的 HTTP 请求,其他方法可用于:contentType(MediaType)contentLength(long)

If necessary, the HTTP request can be manipulated by adding request headers with header(String, String), headers(Consumer<HttpHeaders>, or with the convenience methods accept(MediaType…​), acceptCharset(Charset…​) and so on. For HTTP requests that can contain a body (POST, PUT, and PATCH), additional methods are available: contentType(MediaType), and contentLength(long).

可以设置请求本身正文通过 body(Object),它在内部使用 HTTP Message Conversion。或者,可以使用 ParameterizedTypeReference 来设置请求正文,允许你使用泛型。最后,正文可以设置成写入 OutputStream 的一个回调函数。

The request body itself can be set by body(Object), which internally uses HTTP Message Conversion. Alternatively, the request body can be set using a ParameterizedTypeReference, allowing you to use generics. Finally, the body can be set to a callback function that writes to an OutputStream.

Retrieving the response

一旦设置好请求,可以通过调用 retrieve() 来访问 HTTP 响应。响应正文可以通过使用 body(Class) 或对于参数化类型(如列表) body(ParameterizedTypeReference) 来访问。 body 方法将响应内容转换为各种类型——例如,字节可以转换为 String,JSON 可以使用 Jackson 转换为对象,等等(参见 HTTP Message Conversion)。

Once the request has been set up, the HTTP response is accessed by invoking retrieve(). The response body can be accessed by using body(Class) or body(ParameterizedTypeReference) for parameterized types like lists. The body method converts the response contents into various types – for instance, bytes can be converted into a String, JSON can be converted into objects using Jackson, and so on (see HTTP Message Conversion).

响应还可以转换为 ResponseEntity,从而可以访问响应头以及响应正文。

The response can also be converted into a ResponseEntity, giving access to the response headers as well as the body.

此示例展示了如何使用 RestClient 来执行一个简单的 GET 请求。

This sample shows how RestClient can be used to perform a simple GET request.

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

System.out.println(result); 5
1 Set up a GET request
2 Specify the URL to connect to
3 Retrieve the response
4 Convert the response into a string
5 Print the result
Kotlin
val result= restClient.get() 1
  .uri("https://example.com") 2
  .retrieve() 3
  .body<String>() 4

println(result) 5
6 Set up a GET request
7 Specify the URL to connect to
8 Retrieve the response
9 Convert the response into a string
10 Print the result

可以访问响应状态代码和头通过 ResponseEntity

Access to the response status code and headers is provided through ResponseEntity:

Java
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 Set up a GET request for the specified URL
2 Convert the response into a ResponseEntity
3 Print the result
Kotlin
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
4 Set up a GET request for the specified URL
5 Convert the response into a ResponseEntity
6 Print the result

RestClient 可以使用 Jackson 库将 JSON 转换为对象。注意在此示例中 URI 变量的用法以及 Accept 头被设置为 JSON。

RestClient can convert JSON to objects, using the Jackson library. Note the usage of URI variables in this sample and that the Accept header is set to JSON.

Java
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 Using URI variables
2 Set the Accept header to application/json
3 Convert the JSON response into a Pet domain object
Kotlin
val id = ...
val pet = restClient.get()
  .uri("https://petclinic.example.com/pets/{id}", id) 1
  .accept(APPLICATION_JSON) 2
  .retrieve()
  .body<Pet>() 3
4 Using URI variables
5 Set the Accept header to application/json
6 Convert the JSON response into a Pet domain object

在下一个示例中,RestClient 用于执行一个包含 JSON 的 POST 请求,它同样使用 Jackson 进行了转换。

In the next sample, RestClient is used to perform a POST request that contains JSON, which again is converted using Jackson.

Java
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 Create a Pet domain object
2 Set up a POST request, and the URL to connect to
3 Set the Content-Type header to application/json
4 Use pet as the request body
5 Convert the response into a response entity with no body.
Kotlin
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
6 Create a Pet domain object
7 Set up a POST request, and the URL to connect to
8 Set the Content-Type header to application/json
9 Use pet as the request body
10 Convert the response into a response entity with no body.

Error handling

默认情况下,在检索响应状态代码为 4xx 或 5xx 时,RestClient 会抛出一个 RestClientException 子类。此行为可以使用 onStatus 来覆盖。

By default, RestClient throws a subclass of RestClientException when retrieving a response with a 4xx or 5xx status code. This behavior can be overridden using onStatus.

Java
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 Create a GET request for a URL that returns a 404 status code
2 Set up a status handler for all 4xx status codes
3 Throw a custom exception
Kotlin
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>()
4 Create a GET request for a URL that returns a 404 status code
5 Set up a status handler for all 4xx status codes
6 Throw a custom exception

Exchange

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

For more advanced scenarios, the RestClient gives access to the underlying HTTP request and response through the exchange() method, which can be used instead of retrieve(). Status handlers are not applied when use exchange(), because the exchange function already provides access to the full response, allowing you to perform any error handling necessary.

Java
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 provides the request and response
2 Throw an exception when the response has a 4xx status code
3 Convert the response into a Pet domain object
Kotlin
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
    }
  }
4 exchange provides the request and response
5 Throw an exception when the response has a 4xx status code
6 Convert the response into a Pet domain object

HTTP Message Conversion

Jackson JSON Views

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

To serialize only a subset of the object properties, you can specify a Jackson JSON View, as the following example shows:

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

Multipart

为了发送多部分数据,你需要提供一个 MultiValueMap<String,Object>,其值可以是内容的部分的 Object、文件部分的 Resource、或者带有头的内容部分的 HttpEntity。例如:

To send multipart data, you need to provide a MultiValueMap<String, Object> whose values may be an Object for part content, a Resource for a file part, or an HttpEntity for part content with headers. For example:

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-Type。内容类型会根据用来序列化的 HttpMessageConverter 自动确定,或者在 Resource 的情况下,会根据文件扩展名确定。如果需要,你可以使用 HttpEntity 包装显式提供 MediaType

In most cases, you do not have to specify the Content-Type for each part. The content type is determined automatically based on the HttpMessageConverter chosen to serialize it or, in the case of a Resource, based on the file extension. If necessary, you can explicitly provide the MediaType with an HttpEntity wrapper.

一旦 MultiValueMap 准备就绪,就可以使用 RestClient.post().body(parts)(或 RestTemplate.postForObject)将其用作 POST 请求的正文。

Once the MultiValueMap is ready, you can use it as the body of a POST request, using RestClient.post().body(parts) (or RestTemplate.postForObject).

如果 MultiValueMap 含有至少一个非 String 值,那么 Content-Type 会被 FormHttpMessageConverter 设置为 multipart/form-data。如果 MultiValueMapString 值,则 Content-Type 会被默认设置为 application/x-www-form-urlencoded。如果需要,Content-Type 也可被显式设置。

If the MultiValueMap contains at least one non-String value, the Content-Type is set to multipart/form-data by the FormHttpMessageConverter. If the MultiValueMap has String values, the Content-Type defaults to application/x-www-form-urlencoded. If necessary the Content-Type may also be set explicitly.

Client Request Factories

为了执行 HTTP 请求,RestClient 使用一个客户端 HTTP 库。这些库是通过 ClientRequestFactory 接口适配的。有许多实现可用:

To execute the HTTP request, RestClient uses a client HTTP library. These libraries are adapted via the ClientRequestFactory interface. Various implementations are available:

  • JdkClientHttpRequestFactory for Java’s HttpClient

  • HttpComponentsClientHttpRequestFactory for use with Apache HTTP Components HttpClient

  • JettyClientHttpRequestFactory for Jetty’s HttpClient

  • ReactorNettyClientRequestFactory for Reactor Netty’s HttpClient

  • SimpleClientHttpRequestFactory as a simple default

如果在构建 RestClient 时未指定请求工厂,则如果类路径上可用,它将使用 Apache 或 Jetty HttpClient。否则,如果 java.net.http 模块被加载,它将使用 Java 的 HttpClient。最后,它将诉求到简单的默认值。

If no request factory is specified when the RestClient was built, it will use the Apache or Jetty HttpClient if they are available on the classpath. Otherwise, if the java.net.http module is loaded, it will use Java’s HttpClient. Finally, it will resort to the simple default.

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

Note that the SimpleClientHttpRequestFactory may raise an exception when accessing the status of a response that represents an error (e.g. 401). If this is an issue, use any of the alternative request factories.

WebClient

WebClient 是用于执行 HTTP 请求的非阻塞反应式客户端。它在 5.0 中引入,并且为 RestTemplate 提供了一种选择,支持同步、异步和流式处理场景。

WebClient is a non-blocking, reactive client to perform HTTP requests. It was introduced in 5.0 and offers an alternative to the RestTemplate, with support for synchronous, asynchronous, and streaming scenarios.

WebClient 支持以下内容:

WebClient supports the following:

  • Non-blocking I/O

  • Reactive Streams back pressure

  • High concurrency with fewer hardware resources

  • Functional-style, fluent API that takes advantage of Java 8 lambdas

  • Synchronous and asynchronous interactions

  • Streaming up to or streaming down from a server

有关更多详细信息,请参阅WebClient

See WebClient for more details.

RestTemplate

RestTemplate 提供了 HTTP 客户端库的高级别 API,其形式为传统的 Spring Template 类,它提供了以下重载方法组:

The RestTemplate provides a high-level API over HTTP client libraries in the form of a classic Spring Template class. It exposes the following groups of overloaded methods:

RestClient 为同步 HTTP 访问提供了一个更现代的 API。对于异步和流式处理场景,请考虑使用响应式的 WebClient

The RestClient offers a more modern API for synchronous HTTP access. For asynchronous and streaming scenarios, consider the reactive WebClient.

Table 1. RestTemplate methods
Method group Description

getForObject

Retrieves a representation via GET.

getForEntity

Retrieves a ResponseEntity (that is, status, headers, and body) by using GET.

headForHeaders

Retrieves all headers for a resource by using HEAD.

postForLocation

Creates a new resource by using POST and returns the Location header from the response.

postForObject

Creates a new resource by using POST and returns the representation from the response.

postForEntity

Creates a new resource by using POST and returns the representation from the response.

put

Creates or updates a resource by using PUT.

patchForObject

Updates a resource by using PATCH and returns the representation from the response. Note that the JDK HttpURLConnection does not support PATCH, but Apache HttpComponents and others do.

delete

Deletes the resources at the specified URI by using DELETE.

optionsForAllow

Retrieves allowed HTTP methods for a resource by using ALLOW.

exchange

More generalized (and less opinionated) version of the preceding methods that provides extra flexibility when needed. It accepts a RequestEntity (including HTTP method, URL, headers, and body as input) and returns a ResponseEntity.

These methods allow the use of ParameterizedTypeReference instead of Class to specify a response type with generics.

execute

The most generalized way to perform a request, with full control over request preparation and response extraction through callback interfaces.

Initialization

RestTemplate 使用与 RestClient 相同的 HTTP 库抽象,它默认使用 SimpleClientHttpRequestFactory,但这可以通过构造函数进行更改,请参见 Client Request Factories

RestTemplate uses the same HTTP library abstraction as RestClient. By default, it uses the SimpleClientHttpRequestFactory, but this can be changed via the constructor. See Client Request Factories.

RestTemplate 可用于仪表,以生成度量和跟踪。请参见 RestTemplate Observability support 部分。

RestTemplate can be instrumented for observability, in order to produce metrics and traces. See the RestTemplate Observability support section.

Body

传递到 RestTemplate 方法和从其返回的对象将借助 HttpMessageConverter 转换为 HTTP 消息并从中进行转换,请参见 HTTP Message Conversion

Objects passed into and returned from RestTemplate methods are converted to and from HTTP messages with the help of an HttpMessageConverter, see HTTP Message Conversion.

Migrating from RestTemplate to RestClient

下表显示了 RestClient 等效于 RestTemplate 方法的内容,它可用于从后者迁移到前者。

The following table shows RestClient equivalents for RestTemplate methods. It can be used to migrate from the latter to the former.

Table 2. RestClient equivalents for RestTemplate methods
RestTemplate method RestClient equivalent

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) <<`HttpEntity` headers and body have to be supplied to the RestClient via headers(Consumer<HttpHeaders>) and body(Object).>>

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

method(HttpMethod) .uri(String, Map) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(Class) <<`HttpEntity` headers and body have to be supplied to the RestClient via headers(Consumer<HttpHeaders>) and body(Object).>>

exchange(URI, HttpMethod, HttpEntity, Class)

method(HttpMethod) .uri(URI) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(Class) <<`HttpEntity` headers and body have to be supplied to the RestClient via headers(Consumer<HttpHeaders>) and body(Object).>>

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

method(HttpMethod) .uri(String, Object…​) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(ParameterizedTypeReference) <<`HttpEntity` headers and body have to be supplied to the RestClient via headers(Consumer<HttpHeaders>) and body(Object).>>

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

method(HttpMethod) .uri(String, Map) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(ParameterizedTypeReference) <<`HttpEntity` headers and body have to be supplied to the RestClient via headers(Consumer<HttpHeaders>) and body(Object).>>

exchange(URI, HttpMethod, HttpEntity, ParameterizedTypeReference)

method(HttpMethod) .uri(URI) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(ParameterizedTypeReference) <<`HttpEntity` headers and body have to be supplied to the RestClient via headers(Consumer<HttpHeaders>) and body(Object).>>

exchange(RequestEntity, Class)

method(HttpMethod) .uri(URI) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(Class) <<`RequestEntity` method, URI, headers and body have to be supplied to the RestClient via method(HttpMethod), uri(URI), headers(Consumer<HttpHeaders>) and body(Object).>>

exchange(RequestEntity, ParameterizedTypeReference)

method(HttpMethod) .uri(URI) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(ParameterizedTypeReference) <<`RequestEntity` method, URI, headers and body have to be supplied to the RestClient via method(HttpMethod), uri(URI), headers(Consumer<HttpHeaders>) and body(Object).>>

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 Interface

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

The Spring Framework lets you define an HTTP service as a Java interface with @HttpExchange methods. You can pass such an interface to HttpServiceProxyFactory to create a proxy which performs requests through an HTTP client such as RestClient or WebClient. You can also implement the interface from an @Controller for server request handling.

首先使用带有 @HttpExchange 方法创建接口:

Start by creating the interface with @HttpExchange methods:

interface RepositoryService {

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

	// more HTTP exchange methods...

}

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

Now you can create a proxy that performs requests when methods are called.

对于 RestClient

For 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

For 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

For 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 is supported at the type level where it applies to all methods:

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

}

Method Parameters

带注释的 HTTP 交换方法支持带有以下方法参数的灵活方法签名:

Annotated, HTTP exchange methods support flexible method signatures with the following method parameters:

Method argument Description

URI

Dynamically set the URL for the request, overriding the annotation’s url attribute.

UriBuilderFactory

Provide a UriBuilderFactory to expand the URI template and URI variables with. In effect, replaces the UriBuilderFactory (and its base URL) of the underlying client.

HttpMethod

Dynamically set the HTTP method for the request, overriding the annotation’s method attribute

@RequestHeader

Add a request header or multiple headers. The argument may be a Map<String, ?> or MultiValueMap<String, ?> with multiple headers, a Collection<?> of values, or an individual value. Type conversion is supported for non-String values.

@PathVariable

Add a variable for expand a placeholder in the request URL. The argument may be a Map<String, ?> with multiple variables, or an individual value. Type conversion is supported for non-String values.

@RequestAttribute

Provide an Object to add as a request attribute. Only supported by RestClient and WebClient.

@RequestBody

Provide the body of the request either as an Object to be serialized, or a Reactive Streams Publisher such as Mono, Flux, or any other async type supported through the configured ReactiveAdapterRegistry.

@RequestParam

Add a request parameter or multiple parameters. The argument may be a Map<String, ?> or MultiValueMap<String, ?> with multiple parameters, a Collection<?> of values, or an individual value. Type conversion is supported for non-String values.

When "content-type" is set to "application/x-www-form-urlencoded", request parameters are encoded in the request body. Otherwise, they are added as URL query parameters.

@RequestPart

Add a request part, which may be a String (form field), Resource (file part), Object (entity to be encoded, e.g. as JSON), HttpEntity (part content and headers), a Spring Part, or Reactive Streams Publisher of any of the above.

MultipartFile

Add a request part from a MultipartFile, typically used in a Spring MVC controller where it represents an uploaded file.

@CookieValue

Add a cookie or multiple cookies. The argument may be a Map<String, ?> or MultiValueMap<String, ?> with multiple cookies, a Collection<?> of values, or an individual value. Type conversion is supported for non-String values.

Return Values

受支持的返回值取决于底层客户端。

The supported return values depend on the underlying client.

适用于 HttpExchangeAdapter(如 RestClientRestTemplate)的客户端支持同步返回值:

Clients adapted to HttpExchangeAdapter such as RestClient and RestTemplate support synchronous return values:

Method return value Description

void

Perform the given request.

HttpHeaders

Perform the given request and return the response headers.

<T>

Perform the given request and decode the response content to the declared return type.

ResponseEntity<Void>

Perform the given request and return a ResponseEntity with the status and headers.

ResponseEntity<T>

Perform the given request, decode the response content to the declared return type, and return a ResponseEntity with the status, headers, and the decoded body.

适用于 ReactorHttpExchangeAdapter(如 WebClient)的客户端支持以上所有内容以及响应式变体,下表显示了 Reactor 类型,但您还可以使用 ReactiveAdapterRegistry 支持的其他响应式类型:

Clients adapted to ReactorHttpExchangeAdapter such as WebClient, support all of above as well as reactive variants. The table below shows Reactor types, but you can also use other reactive types that are supported through the ReactiveAdapterRegistry:

Method return value Description

Mono<Void>

Perform the given request, and release the response content, if any.

Mono<HttpHeaders>

Perform the given request, release the response content, if any, and return the response headers.

Mono<T>

Perform the given request and decode the response content to the declared return type.

Flux<T>

Perform the given request and decode the response content to a stream of the declared element type.

Mono<ResponseEntity<Void>>

Perform the given request, and release the response content, if any, and return a ResponseEntity with the status and headers.

Mono<ResponseEntity<T>>

Perform the given request, decode the response content to the declared return type, and return a ResponseEntity with the status, headers, and the decoded body.

Mono<ResponseEntity<Flux<T>>

Perform the given request, decode the response content to a stream of the declared element type, and return a ResponseEntity with the status, headers, and the decoded response body stream.

默认情况下,带有 ReactorHttpExchangeAdapter 的同步返回值的超时取决于底层 HTTP 客户端的配置方式,您还可以在适配器级别设置 blockTimeout 值,但我们建议依赖于底层 HTTP 客户端的超时设置,它在更低级别操作并提供更多控制。

By default, the timeout for synchronous return values with ReactorHttpExchangeAdapter depends on how the underlying HTTP client is configured. You can set a blockTimeout value on the adapter level as well, but we recommend relying on timeout settings of the underlying HTTP client, which operates at a lower level and provides more control.

Error Handling

为了自定义错误响应处理,您需要配置底层 HTTP 客户端。

To customize error response handling, you need to configure the underlying HTTP client.

对于 RestClient

For RestClient:

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

By default, RestClient raises RestClientException for 4xx and 5xx HTTP status codes. To customize this, register a response status handler that applies to all responses performed through the client:

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

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

有关更多详细信息和选项(例如抑制错误状态代码),请参阅 RestClient.BuilderdefaultStatusHandler 的 Javadoc。

For more details and options, such as suppressing error status codes, see the Javadoc of defaultStatusHandler in RestClient.Builder.

对于 WebClient

For WebClient:

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

By default, WebClient raises WebClientResponseException for 4xx and 5xx HTTP status codes. To customize this, register a response status handler that applies to all responses performed through the client:

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

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

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

For more details and options, such as suppressing error status codes, see the Javadoc of defaultStatusHandler in WebClient.Builder.

对于 RestTemplate

For RestTemplate:

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

By default, RestTemplate raises RestClientException for 4xx and 5xx HTTP status codes. To customize this, register an error handler that applies to all responses performed through the client:

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

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

有关更多详细信息和选项,请参阅 RestTemplatesetErrorHandler 的 Javadoc 以及 ResponseErrorHandler 层级结构。

For more details and options, see the Javadoc of setErrorHandler in RestTemplate and the ResponseErrorHandler hierarchy.