1. 概述
在本教程中,我們將學習如何實現 Spring RestTemplate 攔截器。
我們將通過一個示例,創建一個攔截器,該攔截器會將自定義標頭添加到響應中。
2. Interceptor 使用場景
除了請求頭修改之外,RestTemplate 攔截器在以下場景中也很有用:
- 請求和響應日誌記錄
- 使用可配置的退避策略重試請求
- 基於某些請求參數拒絕請求
- 修改請求 URL 地址
3. 創建攔截器
在大多數編程範式中,攔截器是使程序員能夠通過攔截執行的關鍵組成部分。 Spring 框架也支持各種目的的攔截器。Spring RestTemplate 允許我們添加實現 ClientHttpRequestInterceptorClientHttpRequestInterceptor 接口,該接口的 intercept(HttpRequest, byte[], ClientHttpRequestExecution)方法將攔截給定的請求並返回響應,從而提供對request、body和execution對象訪問權限。
我們將使用ClientHttpRequestExecution參數來執行實際操作,並將請求傳遞到後續的執行鏈。
作為第一步,讓我們創建一個實現ClientHttpRequestInterceptor接口的攔截器類:
public class RestTemplateHeaderModifierInterceptor
implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(
HttpRequest request,
byte[] body,
ClientHttpRequestExecution execution) throws IOException {
ClientHttpResponse response = execution.execute(request, body);
response.getHeaders().add("Foo", "bar");
return response;
}
}攔截器將在每個發出的請求上被調用,並且它會將自定義標頭 Foo 添加到每個響應中,在執行完成後並返回時。
由於 intercept() 方法包含了 request 和 body 作為參數,因此還可以根據某些條件對請求進行修改,甚至拒絕請求執行。
4. 設置 RestTemplate
現在我們已經創建了攔截器,接下來我們創建 RestTemplate Bean 並將其與我們的攔截器關聯起來:
@Configuration
public class RestClientConfig {
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
List<ClientHttpRequestInterceptor> interceptors
= restTemplate.getInterceptors();
if (CollectionUtils.isEmpty(interceptors)) {
interceptors = new ArrayList<>();
}
interceptors.add(new RestTemplateHeaderModifierInterceptor());
restTemplate.setInterceptors(interceptors);
return restTemplate;
}
}在某些情況下,RestTemplate 對象可能已經添加了攔截器。為了確保一切按預期工作,我們的代碼只會初始化攔截器列表,如果它為空時。
正如我們的代碼所示,我們使用默認構造函數創建 RestTemplate 對象,但在某些情況下,我們需要兩次讀取請求/響應流。
例如,如果我們希望攔截器作為請求/響應日誌記錄器使用,則需要兩次讀取它——第一次由攔截器讀取,第二次由客户端讀取。
默認實現允許我們僅一次讀取響應流。為了滿足此類特定場景,Spring 提供了名為 BufferingClientHttpRequestFactory 的特殊類。正如其名稱所示,此類將在 JVM 內存中對請求/響應進行緩衝,以便多次使用。
以下是如何使用 BufferingClientHttpRequestFactory 初始化 RestTemplate 對象,以啓用請求/響應流緩存:
RestTemplate restTemplate
= new RestTemplate(
new BufferingClientHttpRequestFactory(
new SimpleClientHttpRequestFactory()
)
);5. 測試我們的示例
以下是用於測試我們 RestTemplate 攔截器的 JUnit 測試用例:
public class RestTemplateItegrationTest {
@Autowired
RestTemplate restTemplate;
@Test
public void givenRestTemplate_whenRequested_thenLogAndModifyResponse() {
LoginForm loginForm = new LoginForm("username", "password");
HttpEntity<LoginForm> requestEntity
= new HttpEntity<LoginForm>(loginForm);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<String> responseEntity
= restTemplate.postForEntity(
"http://httpbin.org/post", requestEntity, String.class
);
Assertions.assertEquals(responseEntity.getStatusCode(), HttpStatus.OK);
Assertions.assertEquals(responseEntity.getHeaders()
.get("Foo")
.get(0), "bar");
}
}在此,我們使用了免費託管的 HTTP 請求和響應服務 http://httpbin.org 來發布我們的數據。 此測試服務將返回我們的請求主體以及一些元數據。
6. 結論
本教程主要講解如何設置攔截器並將其添加到 RestTemplate 對象中。 這種攔截器也可用於過濾、監控和控制發出的請求。RestTemplate 攔截器的一個常見應用場景是添加請求頭,我們在本文中對此進行了詳細説明。