REST 客户端

Spring 框架提供以下选项来调用 REST 端点:

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

  • WebClient - 具有流畅 API 的非阻塞式响应式客户端。

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

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

RestClient

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

创建RestClient

RestClient 是使用其中一个静态create方法创建的。您还可以使用builder()获得一个具有更多选项的构建器,例如指定要使用的 HTTP 库(参见客户端请求工厂)和要使用的消息转换器(参见HTTP 消息转换),设置默认 URI、默认路径变量、默认请求标头或uriBuilderFactory,或注册拦截器和初始化器。

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

以下示例显示了如何创建一个默认的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")
  .defaultCookie("My-Cookie", "Bar")
  .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")
  .defaultCookie("My-Cookie", "Bar")
  .requestInterceptor(myCustomInterceptor)
  .requestInitializer(myCustomInitializer)
  .build()

使用RestClient

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

请求 URL

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

  • 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 默认情况下是编码的,但这可以通过使用自定义uriBuilderFactory构建客户端来更改。URL 也可以使用函数或java.net.URI提供,两者都不进行编码。有关使用和编码 URI 的更多详细信息,请参见URI 链接

请求头和请求体

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

请求体本身可以通过body(Object)设置,它内部使用HTTP 消息转换。或者,可以使用ParameterizedTypeReference设置请求体,允许您使用泛型。最后,可以将请求体设置为写入OutputStream的回调函数。

检索响应

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

响应还可以转换为ResponseEntity,从而可以访问响应头和响应体。

此示例显示了如何使用RestClient执行简单的GET请求。

  • 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 变量的使用,以及将Accept标头设置为 JSON。

  • 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 Accept标头设置为application/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 Accept标头设置为application/json
3 将 JSON 响应转换为Pet领域对象

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

  • 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-Type标头设置为application/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-Type标头设置为application/json
4 使用pet作为请求体
5 将响应转换为没有正文的响应实体。

错误处理

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

  • 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 抛出一个自定义异常

交换

对于更高级的场景,RestClient 通过exchange() 方法访问底层的 HTTP 请求和响应,该方法可以替代retrieve() 使用。使用exchange() 时不应用状态处理程序,因为 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 消息转换

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

多部分

要发送多部分数据,您需要提供一个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));

// send using RestClient.post or RestTemplate.postForEntity

在大多数情况下,您不必为每个部分指定Content-Type。内容类型会根据选择的用于序列化的HttpMessageConverter 自动确定,或者对于Resource,则根据文件扩展名确定。如有必要,您可以使用HttpEntity 包装器显式提供MediaType

准备好MultiValueMap 后,您可以将其用作POST 请求的主体,使用RestClient.post().body(parts)(或RestTemplate.postForObject)。

如果MultiValueMap 包含至少一个非String 值,则FormHttpMessageConverter 会将Content-Type 设置为multipart/form-data。如果MultiValueMap 具有String 值,则Content-Type 默认设置为application/x-www-form-urlencoded。如有必要,也可以显式设置Content-Type

客户端请求工厂

要执行 HTTP 请求,RestClient 使用客户端 HTTP 库。这些库通过ClientRequestFactory 接口进行适配。有多种实现可用

  • JdkClientHttpRequestFactory 用于 Java 的HttpClient

  • HttpComponentsClientHttpRequestFactory 用于 Apache HTTP Components HttpClient

  • JettyClientHttpRequestFactory 用于 Jetty 的HttpClient

  • ReactorNettyClientRequestFactory 用于 Reactor Netty 的HttpClient

  • SimpleClientHttpRequestFactory 作为简单的默认值

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

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

WebClient

WebClient 是一个非阻塞的反应式客户端,用于执行 HTTP 请求。它在 5.0 版本中引入,并提供了一种替代RestTemplate 的方法,支持同步、异步和流式场景。

WebClient 支持以下功能:

  • 非阻塞 I/O

  • 反应式流背压

  • 使用较少的硬件资源实现高并发

  • 利用 Java 8 lambda 表达式的函数式风格、流畅的 API

  • 同步和异步交互

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

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

RestTemplate

RestTemplate 以经典的 Spring 模板类的形式,提供对 HTTP 客户端库的高级 API。它公开了以下几组重载方法:

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

getForObject

通过 GET 检索表示。

getForEntity

通过使用 GET 检索ResponseEntity(即状态、标头和正文)。

headForHeaders

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

postForLocation

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

postForObject

通过使用 POST 创建新的资源,并返回响应中的表示。

postForEntity

通过使用 POST 创建新的资源,并返回响应中的表示。

put

通过使用 PUT 创建或更新资源。

patchForObject

通过使用 PATCH 更新资源,并返回响应中的表示。请注意,JDK HttpURLConnection 不支持PATCH,但 Apache HttpComponents 等支持。

delete

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

optionsForAllow

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

exchange

前面方法的更通用(且更少限定)版本,在需要时提供额外的灵活性。它接受RequestEntity(包括 HTTP 方法、URL、标头和正文作为输入)并返回ResponseEntity

这些方法允许使用ParameterizedTypeReference 代替Class 来指定带有泛型的响应类型。

execute

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

初始化

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

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

主体

传入和传出RestTemplate 方法的对象在HttpMessageConverter 的帮助下转换为 HTTP 消息,请参阅HTTP 消息转换

RestTemplate 迁移到RestClient

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

表 2. 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 框架允许您使用@HttpExchange方法将HTTP服务定义为Java接口。您可以将此接口传递给HttpServiceProxyFactory以创建一个代理,该代理通过HTTP客户端(例如RestClientWebClient)执行请求。您也可以从@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

提供一个UriBuilderFactory来扩展URI模板和URI变量。实际上,它替换了底层客户端的UriBuilderFactory(及其基准URL)。

HttpMethod

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

@RequestHeader

添加一个或多个请求头。参数可以是具有多个头的Map<String, ?>MultiValueMap<String, ?>,一个Collection<?>值,或单个值。支持非字符串值的类型转换。这将覆盖注释的headers属性。

@PathVariable

添加一个变量来扩展请求URL中的占位符。参数可以是具有多个变量的Map<String, ?>,或单个值。支持非字符串值的类型转换。

@RequestAttribute

提供一个Object作为请求属性添加。仅RestClientWebClient支持。

@RequestBody

提供请求的主体,可以是待序列化的对象,也可以是Reactive Streams 的Publisher,例如MonoFlux或通过配置的ReactiveAdapterRegistry支持的任何其他异步类型。

@RequestParam

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

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

@RequestPart

添加请求部分,可以是String(表单字段)、Resource(文件部分)、Object(要编码的实体,例如JSON)、HttpEntity(部分内容和头)、Spring Part或上述任何内容的Reactive Streams Publisher

MultipartFile

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

@CookieValue

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

方法参数不能为null,除非required属性(如果参数注释中可用)设置为false,或者根据MethodParameter#isOptional确定参数为可选。

返回值

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

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

方法返回值 描述

void

执行给定的请求。

HttpHeaders

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

<T>

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

ResponseEntity<Void>

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

ResponseEntity<T>

执行给定的请求,将响应内容解码为声明的返回类型,并返回带有状态、头和已解码主体的ResponseEntity

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

方法返回值 描述

Mono<Void>

执行给定的请求,并释放响应内容(如有)。

Mono<HttpHeaders>

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

Mono<T>

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

Flux<T>

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

Mono<ResponseEntity<Void>>

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

Mono<ResponseEntity<T>>

执行给定的请求,将响应内容解码为声明的返回类型,并返回带有状态、头和已解码主体的ResponseEntity

Mono<ResponseEntity<Flux<T>>

执行给定的请求,将响应内容解码为声明的元素类型的流,并返回带有状态、头和已解码响应主体流的ResponseEntity

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

错误处理

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

对于RestClient

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

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

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

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

对于WebClient

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

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

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

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

对于RestTemplate

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

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

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

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


1。必须通过headers(Consumer<HttpHeaders>)body(Object)HttpEntity头和主体提供给RestClient
2RequestEntity方法、URI、头和主体必须通过method(HttpMethod)uri(URI)headers(Consumer<HttpHeaders>)body(Object)提供给RestClient