使用HttpComponentsClientHttpRequestFactory

时间:2018-03-14 04:08:22

标签: java spring-boot spring-rest

我需要在所有RestTemplate客户端请求中添加自定义标头。所以我实施了ClientHttpRequestInterceptor。我在我的RestTemplateBuilder配置中添加了拦截器,如下所示。问题是,当RestTemplate进行HTTP调用时,它会抛出异常:

java.lang.ClassCastException: org.springframework.http.client.InterceptingClientHttpRequestFactory cannot be cast to org.springframework.http.client.HttpComponentsClientHttpRequestFactory

RestTemplate Bean创建:

@Bean
  public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
    PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager();
    poolingConnectionManager.setMaxTotal(restTemplateProps.getMaxConnectionsPerPool());
    poolingConnectionManager.setDefaultMaxPerRoute(restTemplateProps.getMaxDefaultConnectionPerRoute());
    CloseableHttpClient client = HttpClientBuilder.create().setConnectionManager(poolingConnectionManager).build();
    ClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(client);
    restTemplateBuilder = restTemplateBuilder.additionalInterceptors(new MyClientHttpRequestInterceptor());
    return restTemplateBuilder.requestFactory(clientHttpRequestFactory).build();
  }

另外,我稍后会在以下代码中更新超时:

  protected void setRestTemplateTimeouts() {

    HttpComponentsClientHttpRequestFactory rf =
        (HttpComponentsClientHttpRequestFactory) restTemplate.getRequestFactory();
    rf.setConnectTimeout(restTemplateProps.getConnectionTimeout());
    rf.setReadTimeout(restTemplateProps.getSocketTimeout());
  }

任何人都可以帮我解决这个问题吗?

2 个答案:

答案 0 :(得分:4)

问题是,我在设置ClientHttpRequestInterceptor后尝试设置连接和读取超时

当我尝试获取&时,我的setRestTemplateTimeouts()方法类型转换requestFactoryHttpComponentsClientHttpRequestFactory,我收到ClassCastException例外,因为restTemplate.getRequestFactory()返回InterceptingClientHttpRequestFactory而不是HttpComponentsClientHttpRequestFactory。这是因为我在 restTemplate 对象中添加了拦截器

解决方法是在设置 拦截器之前设置超时,因为在设置拦截器后无法设置超时。请参考以下代码:

@Bean
  public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
    PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager();
    poolingConnectionManager.setMaxTotal(restTemplateProps.getMaxConnectionsPerPool());
    poolingConnectionManager.setDefaultMaxPerRoute(restTemplateProps.getMaxDefaultConnectionPerRoute());
    CloseableHttpClient client = HttpClientBuilder.create().setConnectionManager(poolingConnectionManager).build();
    HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(client);
    clientHttpRequestFactory.setConnectTimeout(restTemplateProps.getConnectionTimeout());
    clientHttpRequestFactory.setReadTimeout(restTemplateProps.getSocketTimeout());
    restTemplateBuilder = restTemplateBuilder.additionalInterceptors(new MyClientHttpRequestInterceptor());
    return restTemplateBuilder.requestFactory(clientHttpRequestFactory).build();
  }

答案 1 :(得分:0)

这就是我设法让拦截器在不抛出异常的情况下记录请求和响应的方法 - 尝试从关闭的流中读取。

 @Bean
 public RestTemplate getRestTemplateConfig()
            throws KeyStoreException, IOException, UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyManagementException {


        SSLContext context = SSLContextBuilder
                .create()
                .loadKeyMaterial(ResourceUtils.getFile("/opt/cert/keystore.jks"), 
                        "password".toCharArray(),
                        "password".toCharArray())
                .build();

        HttpClient client = HttpClients
                .custom()
                .setSSLContext(context)
                .build();

        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(client);
        RestTemplate restTemplate = new RestTemplate(requestFactory);

       //Provide a buffer for the outgoing/incoming stream, allowing the response body to be read multiple times
        // (if not configured, the interceptor reads the Response stream, and then returns body=null when responding to the data)
        restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(requestFactory));
        restTemplate.setErrorHandler(new RestTemplateResponseErrorHandler());
        restTemplate.setInterceptors(Collections.<ClientHttpRequestInterceptor>singletonList(
                new RestTemplateInterceptor()));
        restTemplate.getMessageConverters().add(jacksonSupportsMoreTypes());
        return restTemplate;
    }

    private HttpMessageConverter jacksonSupportsMoreTypes() {
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.setSupportedMediaTypes(Arrays.asList( MediaType.APPLICATION_OCTET_STREAM));
        return converter;
    }