作者: baeldung
译者:helloworldtang
1. 概览
在这篇文章中,我们将学习如何实现一个Spring RestTemplate 拦截器。
文中将通过一个示例来展示如何创建一个Spring RestTemplate拦截器及如何使用这个拦截器来添加一个自定义HTTP头。
2. 拦截器的使用场景
除了修改HTTP头之外,RestTemplate拦截器还可以用于下面的场景:
- 打印请求和响应日志
- 用可配置的回滚策略进行重试
- 基于某些请求参数来拒绝请求
- 改变请求的URL
3. 创建拦截器
在大多数编程范例中,拦截器是程序员能够通过拦截来控制程序执行的重要途径。基于不同的场景,Spring框架还支持各式各样的拦截器。
Spring RestTemplate允许我们添加实现了ClientHttpRequestInterceptor接口的拦截器。这个接口的intercept(HttpRequest, byte[], ClientHttpRequestExecution)方法将通过让我们访问request、body和execution对象来拦截指定的请求并返回响应。
我们将使用ClientHttpRequestExecution参数来执行实际的操作,并将请求传递给后续的调用链。
首先,让我们创建一个实现了ClientHttpRequestInterceptor接口的拦截器类:
代码语言:javascript复制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;
}
}
我们的拦截器将被用于每个传入的请求,并且一旦执行完成,在返回前,这个拦截器将向每个响应添加一个自定义的HTTP头Foo。
由于intercept()方法的参数签名包含request和body,所以还可以根据某些条件对请求进行任何修改,甚至拒绝请求执行。
4. 配置RestTemplate
既然已经创建了拦截器,那么就让我们在创建RestTemplate bean时添加这个拦截器:
代码语言:javascript复制@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并启用请求/响应流缓存:
代码语言:javascript复制RestTemplate restTemplate
= new RestTemplate(
new BufferingClientHttpRequestFactory(
new SimpleClientHttpRequestFactory()
)
);
5. 测试
下面是测试RestTemplate拦截器的JUnit测试用例:
代码语言:javascript复制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
);
assertThat(
responseEntity.getStatusCode(),
is(equalTo(HttpStatus.OK))
);
assertThat(
responseEntity.getHeaders().get("Foo").get(0),
is(equalTo("bar"))
);
}
}
在上面的例子中,我们将请求数据发送到一个免费托管的HTTP服务器http://httpbin.org。这个测试服务器将返回我们的请求体以及一些元数据。
6. 总结
本教程介绍如何设置拦截器并将其配置到RestTemplate对象中。这种拦截器还可以用于过滤、监控和控制传入的请求。 RestTemplate拦截器的一个常用场景是修改HTTP头——我们已经在本文中详细说明了这一点。
和往常一样,文中用到的示例代码可以在Github项目上找到。这是一个基于maven的项目,因此应该很容易导入和运行。