无法使用带有自定义拦截器的弹簧休息模板发布大文件

时间:2017-06-27 12:56:15

标签: java spring large-files resttemplate

我正尝试使用Spring rest template POST w / custom interceptor将一个大文件从一个微服务发布到另一个微服务,如下所示:

SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setBufferRequestBody(false);
restTemplate = new RestTemplate(requestFactory);
restTemplate.getInterceptors().add({customInterceptor});
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file", {InputStreamResource});
body.add("metadata", {JSON string});
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
restTemplate.exchange({url}, HttpMethod.POST, requestEntity, ...);

(我使用SimpleClientHttpRequestFactory或HttpComponentsClientHttpRequestFactory没有区别)

添加拦截器会导致在调用getRequestFactory时创建新的InterceptingClientHttpRequestFactory(包装原始请求工厂)。

这适用于较小的文件但适用于大型文件 - 因为请求永远不会委托给原始请求工厂,因此不会发生任何流式传输,因此会导致java.lang.OutOfMemoryError: Java heap space异常。

任何帮助都将不胜感激。

2 个答案:

答案 0 :(得分:0)

似乎this issue不会解决RestTemplate的问题

  

既然WebClient可用并且为流提供一流的支持,我们将不再支持它。

请注意,WebClient在Spring 5中可用。

答案 1 :(得分:0)

我也遇到了这个问题,但是在此时无法切换到WebClient,因此我选择了通过实施新的ClientHttpRequestFactory(尽管通过{{ 1}});它之所以起作用,主要是因为我们只调整标题,而不调整正文。

AbstractClientHttpRequestFactoryWrapper

这就是SimpleClientHttpRequestFactory simpleRequestFactory = new SimpleClientHttpRequestFactory(); simpleRequestFactory.setConnectTimeout(10000); simpleRequestFactory.setReadTimeout(60000); simpleRequestFactory.setBufferRequestBody(false); // this enables streaming SomeHeaderInterceptingClientHttpRequestFactory interceptingRequestFactory = new SomeHeaderInterceptingClientHttpRequestFactory(simpleRequestFactory); RestTemplate restTemplate = new RestTemplate(interceptingRequestFactory); 的样子:

SomeHeaderInterceptingClientHttpRequestFactory

如果您想对身体做些事情,那么您也可以尝试实现新的public class SomeHeaderInterceptingClientHttpRequestFactory extends AbstractClientHttpRequestFactoryWrapper { // you can have fields here that are initialized in the constructor // e.g. a service that supplies the header value that you want to populate public SomeHeaderInterceptingClientHttpRequestFactory(ClientHttpRequestFactory requestFactory) { super(requestFactory); // initialize fields } @Override protected ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod, ClientHttpRequestFactory requestFactory) throws IOException { ClientHttpRequest request = requestFactory.createRequest(uri, httpMethod); HttpHeaders headers = request.getHeaders(); headers.set("SOME_HEADER", "some value"); return request; } } 。然后,您将在新引入的ClientHttpRequest的{​​{1}}方法中返回新引入的ClientHttpRequest的新实例。