简介
Spring RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种便捷访问远程Http服务的方法,使用RestTemplate能够快捷简便的调用其他HTTP服务。
在日常使用RestTemplate的过程中,常需要跟踪RestTemplate发出的请求日志,通过分析发出的请求头、请求方法、请求体等信息进行程序调试,本文将介绍如何自定义RestTemplate日志,以便使用时能够更好的通过日志分析进行程序调试。
日志配置类
先创建自定义日志配置类,实现Spring的http客户端拦截器接口:
@Slf4j
public class RestTemplateLoggingRequestInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
traceRequest(request, body);
ClientHttpResponse response = execution.execute(request, body);
traceResponse(response);
return response;
}
private void traceRequest(HttpRequest request, byte[] body) throws IOException {
log.info("-------------请求开始-------------");
log.info("URI : {}", request.getURI());
log.info("Method : {}", request.getMethod());
log.info("Headers : {}", request.getHeaders());
log.info("Request body: {}", new String(body, "UTF-8"));
log.info("-------------请求结束-------------");
}
private void traceResponse(ClientHttpResponse response) throws IOException {
StringBuilder inputStringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody(), "UTF-8"));
String line = bufferedReader.readLine();
while (line != null) {
inputStringBuilder.append(line);
line = bufferedReader.readLine();
}
log.info("-------------应答开始-------------");
log.info("Status code : {}", response.getStatusCode());
log.info("Status text : {}", response.getStatusText());
log.info("Headers : {}", response.getHeaders());
log.info("Response body: {}", inputStringBuilder.toString());
log.info("-------------应答结束-------------");
}
}
配置RestTemplate
编写完自定义日志配置类,还需要将日志配置类设置进RestTemplate中才能使其生效,下面介绍两种配置方式:
使用RestTemplateBuilder:
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate getRestTemplate(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder
.requestFactory(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()))
.additionalInterceptors(new RestTemplateLoggingRequestInterceptor())
.build();
}
}
直接new一个RestTemplate客户端:
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(){
RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
restTemplate.setInterceptors(Arrays.asList(new RestTemplateLoggingRequestInterceptor()));
return restTemplate;
}
}
当然,本文是将RestTemplate注册成了Bean,在需要用到的地方注入依赖即可,如果不需要注册成Bean,在使用到的地方new一个RestTemplate实例出来,根据自己需要配置相关的东西就行了,RestTemplate还有超时时间等其他配置,这里就不过多介绍。
需要注意的是,上面的代码中可以看到,除了配置ClientHttpRequestInterceptor
之外,还配置了RestTemplate的ClientHttpRequestFactory
,这是因为RestTemplate默认使用的是SimpleClientHttpRequestFactory
,它的Body流只能读取一次,如果我们记录日志的时候,把Body读取打印出来,那么接下去在去读Body流的时候读不到就会报错,所以如果需要在日志中记录应答的Body,就可以使用BufferingClientHttpRequestFactory
,它会通过用缓冲流存储请求体的方式,让我们可以多次重复读取Body流。