REST 用戶端

Spring Framework 提供以下選項,用於呼叫 REST 端點

  • RestClient - 具有流暢 API 的同步用戶端。

  • WebClient - 具有流暢 API 的非阻塞、反應式用戶端。

  • RestTemplate - 具有範本方法 API 的同步用戶端。

  • HTTP 介面 - 具有產生的動態 Proxy 實作的註解介面。

RestClient

RestClient 是一種同步 HTTP 用戶端,提供現代化的流暢 API。它提供 HTTP 程式庫的抽象化,可方便地從 Java 物件轉換為 HTTP 請求,並從 HTTP 回應建立物件。

建立 RestClient

RestClient 是使用靜態 create 方法之一建立的。您也可以使用 builder() 取得具有更多選項的 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 連結

請求標頭和 Body

如有必要,可以使用 header(String, String)headers(Consumer<HttpHeaders> 或便利方法 accept(MediaType…​)acceptCharset(Charset…​) 等新增請求標頭來操作 HTTP 請求。對於可以包含 Body 的 HTTP 請求 (POSTPUTPATCH),還有其他方法可用:contentType(MediaType)contentLength(long)

請求 Body 本身可以使用 body(Object) 設定,這會在內部使用HTTP 訊息轉換。或者,可以使用 ParameterizedTypeReference 設定請求 Body,讓您可以使用泛型。最後,Body 可以設定為寫入 OutputStream 的回呼函數。

擷取回應

設定請求後,透過叫用 retrieve() 存取 HTTP 回應。可以使用 body(Class)body(ParameterizedTypeReference) 存取回應 Body,以用於列表等參數化類型。body 方法將回應內容轉換為各種類型 – 例如,位元組可以轉換為 String,JSON 可以使用 Jackson 轉換為物件,依此類推 (請參閱HTTP 訊息轉換)。

回應也可以轉換為 ResponseEntity,以存取回應標頭以及 Body。

此範例顯示如何使用 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 請求,JSON 再次使用 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 作為請求 Body
5 將回應轉換為沒有 Body 的回應實體。
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 作為請求 Body
5 將回應轉換為沒有 Body 的回應實體。

錯誤處理

預設情況下,當擷取具有 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 擲回自訂例外

Exchange

對於更進階的案例,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();

Multipart

若要傳送 multipart 資料,您需要提供 MultiValueMap<String, Object>,其值可以是 part 內容的 Object、檔案 part 的 Resource 或帶有標頭的 part 內容的 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

在大多數情況下,您不必為每個 part 指定 Content-Type。內容類型會根據選擇用於序列化它的 HttpMessageConverter 自動判斷,或者在 Resource 的情況下,根據檔案副檔名判斷。如有必要,您可以使用 HttpEntity 包裝器明確提供 MediaType

一旦 MultiValueMap 準備就緒,您就可以將其用作 POST 請求的 Body,使用 RestClient.post().body(parts) (或 RestTemplate.postForObject)。

如果 MultiValueMap 包含至少一個非 String 值,則 Content-Type 會由 FormHttpMessageConverter 設定為 multipart/form-data。如果 MultiValueMap 具有 String 值,則 Content-Type 預設為 application/x-www-form-urlencoded。如有必要,也可以明確設定 Content-Type

用戶端請求工廠

為了執行 HTTP 請求,RestClient 使用用戶端 HTTP 程式庫。這些程式庫透過 ClientRequestFactory 介面進行調整。提供各種實作

  • 適用於 Java HttpClientJdkClientHttpRequestFactory

  • 適用於 Apache HTTP Components HttpClientHttpComponentsClientHttpRequestFactory

  • 適用於 Jetty HttpClientJettyClientHttpRequestFactory

  • 適用於 Reactor Netty HttpClientReactorNettyClientRequestFactory

  • 作為簡單預設值的 SimpleClientHttpRequestFactory

如果在建置 RestClient 時未指定請求工廠,如果 Apache 或 Jetty HttpClient 在類別路徑上可用,則會使用它們。否則,如果載入 java.net.http 模組,則會使用 Java HttpClient。最後,它會回復為簡單的預設值。

請注意,當存取表示錯誤 (例如 401) 的回應狀態時,SimpleClientHttpRequestFactory 可能會引發例外。如果這是問題,請使用任何替代請求工廠。

WebClient

WebClient 是一種非阻塞、反應式用戶端,用於執行 HTTP 請求。它在 5.0 中引入,並提供 RestTemplate 的替代方案,支援同步、非同步和串流案例。

WebClient 支援以下功能

  • 非阻塞 I/O

  • 反應式串流回壓

  • 以較少的硬體資源實現高並行性

  • 函數式、流暢的 API,充分利用 Java 8 Lambda

  • 同步和非同步互動

  • 從伺服器串流上傳或串流下載

如需更多詳細資訊,請參閱WebClient

RestTemplate

RestTemplate 以經典 Spring 範本類別的形式,在 HTTP 用戶端程式庫之上提供高階 API。它公開以下幾組多載方法

RestClient 為同步 HTTP 存取提供更現代化的 API。對於非同步和串流案例,請考慮反應式WebClient
表 1. RestTemplate 方法
方法群組 描述

getForObject

透過 GET 擷取表示法。

getForEntity

透過使用 GET 擷取 ResponseEntity (即狀態、標頭和 Body)。

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、標頭和 Body 作為輸入) 並傳回 ResponseEntity

這些方法允許使用 ParameterizedTypeReference 而非 Class 來指定具有泛型的回應類型。

execute

執行請求的最通用方式,透過回呼介面完全控制請求準備和回應擷取。

初始化

RestTemplate 使用與 RestClient 相同的 HTTP 程式庫抽象化。預設情況下,它使用 SimpleClientHttpRequestFactory,但可以透過建構子變更此設定。請參閱用戶端請求工廠

可以檢測 RestTemplate 的可觀察性,以便產生指標和追蹤。請參閱RestTemplate 可觀察性支援章節。

Body

傳遞到 RestTemplate 方法和從方法傳回的物件會借助 HttpMessageConverter 轉換為 HTTP 訊息和從 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 Framework 讓您能將 HTTP 服務定義為具有 @HttpExchange 方法的 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 exchange 方法支援彈性的方法簽章,並具有以下方法參數

方法引數 描述

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

新增請求部分,可以是字串(表單欄位)、Resource(檔案部分)、物件(要編碼的實體,例如,作為 JSON)、HttpEntity(部分內容和標頭)、Spring Part 或上述任何項目的 Reactive Streams Publisher

MultipartFile

MultipartFile 新增請求部分,通常在 Spring MVC 控制器中使用,其中它代表上傳的檔案。

@CookieValue

新增 Cookie 或多個 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

預設情況下,RestClient 會針對 4xx 和 5xx HTTP 狀態碼引發 RestClientException。若要自訂此行為,請註冊適用於透過用戶端執行的所有回應的回應狀態處理常式

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

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

如需更多詳細資訊和選項,例如抑制錯誤狀態碼,請參閱 RestClient.BuilderdefaultStatusHandler 的 Javadoc。

針對 WebClient

預設情況下,WebClient 會針對 4xx 和 5xx HTTP 狀態碼引發 WebClientResponseException。若要自訂此行為,請註冊適用於透過用戶端執行的所有回應的回應狀態處理常式

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

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

如需更多詳細資訊和選項,例如抑制錯誤狀態碼,請參閱 WebClient.BuilderdefaultStatusHandler 的 Javadoc。

針對 RestTemplate

預設情況下,RestTemplate 會針對 4xx 和 5xx HTTP 狀態碼引發 RestClientException。若要自訂此行為,請註冊適用於透過用戶端執行的所有回應的錯誤處理常式

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

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

如需更多詳細資訊和選項,請參閱 RestTemplatesetErrorHandler 的 Javadoc 和 ResponseErrorHandler 階層。


1. HttpEntity 標頭和主體必須透過 headers(Consumer<HttpHeaders>)body(Object) 提供給 RestClient
2. RequestEntity 方法、URI、標頭和主體必須透過 method(HttpMethod)uri(URI)headers(Consumer<HttpHeaders>)body(Object) 提供給 RestClient