REST 客戶端
Spring Framework 提供以下選項來呼叫 REST 端點:
-
RestClient
- 帶有 fluent API 的同步客戶端。 -
WebClient
- 帶有 fluent API 的非阻塞、響應式客戶端。 -
RestTemplate
- 帶有 template method API 的同步客戶端。 -
HTTP Interface - 帶有生成的動態代理實現的註解介面。
RestClient
RestClient
是一個提供現代、fluent API 的同步 HTTP 客戶端。它提供了一個對 HTTP 庫的抽象,可以方便地將 Java 物件轉換為 HTTP 請求,並從 HTTP 響應建立物件。
建立 RestClient
RestClient
是使用靜態的 create
方法之一建立的。您也可以使用 builder()
獲取一個帶有更多選項的構建器,例如指定要使用的 HTTP 庫(參見客戶端請求工廠)和要使用的訊息轉換器(參見HTTP 訊息轉換),設定預設 URI、預設路徑變數、預設請求頭或 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")
.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)
// ...
也可以使用函式來實現更多控制,例如指定請求引數。
String URL 預設會進行編碼,但可以透過使用自定義 uriBuilderFactory
構建客戶端來更改此行為。URL 也可以透過函式或 java.net.URI
提供,這兩者都不會進行編碼。有關處理和編碼 URI 的更多詳細資訊,請參見URI 連結。
請求頭和請求體
如有必要,可以透過 header(String, String)
、headers(Consumer<HttpHeaders>
或便捷方法 accept(MediaType…)
、acceptCharset(Charset…)
等新增請求頭來操作 HTTP 請求。對於可以包含請求體(POST
、PUT
和 PATCH
)的 HTTP 請求,還有其他可用方法:contentType(MediaType)
和 contentLength(long)
。
請求體本身可以透過 body(Object)
設定,它在內部使用HTTP 訊息轉換。另外,請求體可以使用 ParameterizedTypeReference
設定,從而可以使用泛型。最後,請求體可以設定為寫入 OutputStream
的回撥函式。
檢索響應
設定好請求後,可以透過在 retrieve()
之後鏈式呼叫方法來發送。例如,響應體可以透過 retrieve().body(Class)
或針對列表等引數化型別使用 retrieve().body(ParameterizedTypeReference)
訪問。body
方法將響應內容轉換為各種型別——例如,位元組可以轉換為 String
,JSON 可以使用 Jackson 轉換為物件,等等(參見HTTP 訊息轉換)。
響應也可以轉換為 ResponseEntity
,從而可以透過 retrieve().toEntity(Class)
訪問響應頭和響應體。
單獨呼叫 retrieve() 是一個空操作,返回一個 ResponseSpec 。應用必須在 ResponseSpec 上呼叫一個終端操作才能產生任何副作用。如果您的用例對消費響應不感興趣,可以使用 retrieve().toBodilessEntity() 。 |
此示例展示瞭如何使用 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 作為請求體 |
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 | 丟擲自定義異常 |
Exchange
對於更高階的場景,RestClient
透過 exchange()
方法(可以替代 retrieve()
使用)提供了對底層 HTTP 請求和響應的訪問。使用 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 Views
為了僅序列化物件屬性的子集,您可以指定一個Jackson JSON View,如以下示例所示:
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>
,其值可以是用於部分內容的 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
時未指定請求工廠,它將優先使用 classpath 上可用的 Apache 或 Jetty HttpClient
。否則,如果載入了 java.net.http
模組,它將使用 Java 的 HttpClient
。最後,它將回退到簡單的預設實現。
請注意,當訪問表示錯誤的響應狀態(例如 401)時,SimpleClientHttpRequestFactory 可能會丟擲異常。如果這是一個問題,請使用其他任何請求工廠。 |
WebClient
WebClient
是一個非阻塞、響應式的客戶端,用於執行 HTTP 請求。它在 5.0 中引入,提供了 RestTemplate
的替代方案,支援同步、非同步和流式場景。
WebClient
支援以下特性:
-
非阻塞 I/O
-
響應式流背壓
-
以更少的硬體資源實現高併發
-
利用 Java 8 lambda 的函式式風格、fluent API
-
同步和非同步互動
-
向上遊或向下遊流式傳輸
有關更多詳細資訊,請參閱WebClient。
RestTemplate
RestTemplate
以經典的 Spring Template 類的形式提供了對 HTTP 客戶端庫的高階 API。它暴露了以下幾組過載方法:
RestClient 為同步 HTTP 訪問提供了更現代的 API。對於非同步和流式場景,請考慮響應式的WebClient。 |
方法組 | 描述 |
---|---|
|
透過 GET 檢索表示。 |
|
透過 GET 檢索 |
|
透過 HEAD 檢索資源的所有頭部。 |
|
透過 POST 建立新資源並返回響應中的 |
|
透過 POST 建立新資源並返回響應中的表示。 |
|
透過 POST 建立新資源並返回響應中的表示。 |
|
透過 PUT 建立或更新資源。 |
|
透過 PATCH 更新資源並返回響應中的表示。注意 JDK |
|
透過 DELETE 刪除指定 URI 的資源。 |
|
透過 ALLOW 檢索資源允許的 HTTP 方法。 |
|
比上述方法更通用(且更不固執)的版本,在需要時提供額外的靈活性。它接受一個 這些方法允許使用 |
|
執行請求最通用的方式,透過回撥介面完全控制請求準備和響應提取。 |
初始化
RestTemplate
使用與 RestClient
相同的 HTTP 庫抽象。預設情況下,它使用 SimpleClientHttpRequestFactory
,但這可以透過建構函式更改。請參見客戶端請求工廠。
RestTemplate 可以進行觀測,以生成度量和追蹤。請參閱 RestTemplate 可觀測性支援 部分。 |
請求/響應體
傳入和傳出 RestTemplate
方法的物件,藉助 HttpMessageConverter
進行 HTTP 訊息的轉換,請參見 HTTP 訊息轉換。
從 RestTemplate
遷移到 RestClient
下表顯示了 RestClient
對應於 RestTemplate
方法的等效用法。您可以使用它從後者遷移到前者。
RestTemplate 方法 |
RestClient 等效用法 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HTTP 介面
Spring Framework 允許您使用 @HttpExchange
方法將 HTTP 服務定義為 Java 介面。您可以將此類介面傳遞給 HttpServiceProxyFactory
以建立一個代理,該代理透過 RestClient
或 WebClient
等 HTTP 客戶端執行請求。您也可以從 @Controller
實現該介面以處理伺服器請求。
首先建立帶有 @HttpExchange
方法的介面
public 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")
public 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 交換方法支援靈活的方法簽名,使用以下方法引數
方法引數 | 描述 |
---|---|
|
動態設定請求的 URL,覆蓋註解的 |
|
提供一個 |
|
動態設定請求的 HTTP 方法,覆蓋註解的 |
|
新增一個或多個請求頭。引數可以是一個單獨的值,一個 |
|
新增一個變數以擴充套件請求 URL 中的佔位符。引數可以是包含多個變數的 |
|
提供一個 |
|
提供請求體,可以是待序列化的 |
|
新增一個或多個請求引數。引數可以是包含多個引數的 當 |
|
新增請求部分,它可以是 String(表單欄位)、 |
|
從 |
|
新增一個或多個 cookie。引數可以是包含多個 cookie 的 |
方法引數不能為 null
,除非 required
屬性(如果引數註解提供了此屬性)設定為 false
,或者該引數被標記為可選(由 MethodParameter#isOptional
決定)。
自定義引數解析器
對於更復雜的用例,HTTP 介面不支援 RequestEntity
型別作為方法引數。這將接管整個 HTTP 請求,並且不會改進介面的語義。開發者可以將多個方法引數組合到一個自定義型別中,並配置一個專用的 HttpServiceArgumentResolver
實現,而不是新增大量方法引數。
在以下 HTTP 介面中,我們使用自定義 Search
型別作為引數
-
Java
-
Kotlin
public interface RepositoryService {
@GetExchange("/repos/search")
List<Repository> searchRepository(Search search);
}
interface RepositoryService {
@GetExchange("/repos/search")
fun searchRepository(search: Search): List<Repository>
}
我們可以實現自己的 HttpServiceArgumentResolver
來支援自定義 Search
型別,並將其資料寫入 outgoing HTTP 請求中。
-
Java
-
Kotlin
static class SearchQueryArgumentResolver implements HttpServiceArgumentResolver {
@Override
public boolean resolve(Object argument, MethodParameter parameter, HttpRequestValues.Builder requestValues) {
if (parameter.getParameterType().equals(Search.class)) {
Search search = (Search) argument;
requestValues.addRequestParameter("owner", search.owner());
requestValues.addRequestParameter("language", search.language());
requestValues.addRequestParameter("query", search.query());
return true;
}
return false;
}
}
class SearchQueryArgumentResolver : HttpServiceArgumentResolver {
override fun resolve(
argument: Any?,
parameter: MethodParameter,
requestValues: HttpRequestValues.Builder
): Boolean {
if (parameter.getParameterType() == Search::class.java) {
val search = argument as Search
requestValues.addRequestParameter("owner", search.owner)
.addRequestParameter("language", search.language)
.addRequestParameter("query", search.query)
return true
}
return false
}
}
最後,我們可以在設定過程中使用這個引數解析器,並使用我們的 HTTP 介面。
-
Java
-
Kotlin
RestClient restClient = RestClient.builder().baseUrl("https://api.github.com/").build();
RestClientAdapter adapter = RestClientAdapter.create(restClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory
.builderFor(adapter)
.customArgumentResolver(new SearchQueryArgumentResolver())
.build();
RepositoryService repositoryService = factory.createClient(RepositoryService.class);
Search search = Search.create()
.owner("spring-projects")
.language("java")
.query("rest")
.build();
List<Repository> repositories = repositoryService.searchRepository(search);
val restClient = RestClient.builder().baseUrl("https://api.github.com/").build()
val adapter = RestClientAdapter.create(restClient)
val factory = HttpServiceProxyFactory
.builderFor(adapter)
.customArgumentResolver(SearchQueryArgumentResolver())
.build()
val repositoryService = factory.createClient<RepositoryService>(RepositoryService::class.java)
val search = Search(owner = "spring-projects", language = "java", query = "rest")
val repositories = repositoryService.searchRepository(search)
返回值
支援的返回值取決於底層客戶端。
適配 HttpExchangeAdapter
的客戶端(例如 RestClient
和 RestTemplate
)支援同步返回值
方法返回值 | 描述 |
---|---|
|
執行給定的請求。 |
|
執行給定的請求並返回響應頭部。 |
|
執行給定的請求並將響應內容解碼為宣告的返回型別。 |
|
執行給定的請求並返回一個包含狀態和頭部的 |
|
執行給定的請求,將響應內容解碼為宣告的返回型別,並返回一個包含狀態、頭部和解碼後的請求體的 |
適配 ReactorHttpExchangeAdapter
的客戶端(例如 WebClient
)支援上述所有內容以及響應式變體。下表顯示了 Reactor 型別,但您也可以使用透過 ReactiveAdapterRegistry
支援的其他響應式型別
方法返回值 | 描述 |
---|---|
|
執行給定的請求,並釋放(如果存在)響應內容。 |
|
執行給定的請求,釋放(如果存在)響應內容,並返回響應頭部。 |
|
執行給定的請求並將響應內容解碼為宣告的返回型別。 |
|
執行給定的請求,並將響應內容解碼為宣告元素型別的流。 |
|
執行給定的請求,釋放(如果存在)響應內容,並返回一個包含狀態和頭部的 |
|
執行給定的請求,將響應內容解碼為宣告的返回型別,並返回一個包含狀態、頭部和解碼後的請求體的 |
|
執行給定的請求,將響應內容解碼為宣告元素型別的流,並返回一個包含狀態、頭部和解碼後的響應體流的 |
預設情況下,使用 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.Builder
中 defaultStatusHandler
的 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.Builder
中 defaultStatusHandler
的 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();
有關更多詳細資訊和選項,請參閱 RestTemplate
中 setErrorHandler
的 Javadoc 以及 ResponseErrorHandler
層次結構。