经过
为RestTemplate添加LoggingRequestInterceptor后 发送请求 报Attempted read from closed stream错误
根据错误日志得知是执行到IOUtils.toString(response.getBody(), StandardCharsets.UTF_8);报错
debug后发现LoggingRequestInterceptor的intercept方法被执行了两次 从而导致报错
RestTempalteConfig浓缩
@Configuration
@Slf4j
public class RestTemplateConfig {
@Resource
private RestTemplateBuilder restTemplateBuilder;
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = restTemplateBuilder.build();
restTemplate.setRequestFactory(getRequestFactory(restTemplate));
restTemplate.setInterceptors(Collections.singletonList(new LoggingRequestInterceptor()));
return restTemplate;
}
private ClientHttpRequestFactory getRequestFactory(RestTemplate restTemplate) {
ClientHttpRequestFactory requestFactory = restTemplate.getRequestFactory();
return requestFactory instanceof BufferingClientHttpRequestFactory ? requestFactory : new BufferingClientHttpRequestFactory(requestFactory);
}
}
错误代码
private ClientHttpRequestFactory getRequestFactory(RestTemplate restTemplate) {
ClientHttpRequestFactory requestFactory = restTemplate.getRequestFactory();
return requestFactory instanceof BufferingClientHttpRequestFactory ? requestFactory : new BufferingClientHttpRequestFactory(requestFactory);
}
修复代码
private ClientHttpRequestFactory getRequestFactory(RestTemplate restTemplate) {
restTemplate.setInterceptors(Collections.emptyList());
ClientHttpRequestFactory requestFactory = restTemplate.getRequestFactory();
return requestFactory instanceof BufferingClientHttpRequestFactory ? requestFactory : new BufferingClientHttpRequestFactory(requestFactory);
}
问题分析
请求流程
HttpComponentsClientHttpRequest为默认的也有可能是SimpleClientHttpRequestFactory或其它ClientHttpRequestFactory的实现类
@Override
public ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException {
// 是否有下一个插件 责任链
if (this.iterator.hasNext()) {
ClientHttpRequestInterceptor nextInterceptor = this.iterator.next();
return nextInterceptor.intercept(request, body, this);
}else {
// 没有插件了 delegate为被代理的ClientHttpRequestFactory如HttpComponentsClientHttpRequest
ClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), method);
return delegate.execute();
}
}
问题定位
通过debug发现delegate.execute()中的delegate为InterceptingClientHttpRequest类型 而通过RestTemplateBuilder创建的restTemplate为HttpComponentsClientHttpRequest类型 后发现restTemplate.getRequestFactory() 返回的是InterceptingClientHttpRequest类型 显然不是我们想要的 这就是多执行一次的原因 套了一层娃
@Override
public ClientHttpRequestFactory getRequestFactory() {
List<ClientHttpRequestInterceptor> interceptors = getInterceptors();
if (!CollectionUtils.isEmpty(interceptors)) {
ClientHttpRequestFactory factory = this.interceptingRequestFactory;
if (factory == null) {
factory = new InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors);
this.interceptingRequestFactory = factory;
}
return factory;
}
else {
return super.getRequestFactory();
}
}
发现当getInterceptors不为空时会构造interceptingRequestFactory返回
针对这点在修复代码中把Interceptors清空后 在获取 返回真实类型
当然也可以直接创建一个HttpComponentsClientHttpRequest或SimpleClientHttpRequestFactory塞进去