使用RestTemplate POST InputStream

时间:2015-12-02 17:00:40

标签: java resttemplate

我有一个客户端需要将大量的大型json文件POST到服务器。我已经能够通过将每个文件读入内存并使用RestTemplate发布整个文件来使其工作。但是,客户端快速耗尽处理大型json文件的内存。我想切换到流式方法,但无法弄清楚如何正确使用RestInmplate的FileInputStream。我找到了this question并使用了接受的答案中给出的代码,但我仍然看到内存使用和OutOfMemory异常使我相信它没有流式传输文件,但仍然完全将它们读入内存。我究竟做错了什么?这是我目前的情况:

final InputStream fis = ApplicationStore.class.getResourceAsStream(path);

final RequestCallback requestCallback = new RequestCallback() {
    @Override
    public void doWithRequest(final ClientHttpRequest request) throws IOException {
        request.getHeaders().add("Content-type", "application/json");
        IOUtils.copy(fis, request.getBody());
    }
};

final RestTemplate restTemplate = new RestTemplate();
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setBufferRequestBody(false);     
restTemplate.setRequestFactory(requestFactory);     
final HttpMessageConverterExtractor<String> responseExtractor =
         new HttpMessageConverterExtractor<String>(String.class, restTemplate.getMessageConverters());

restTemplate.execute("http://" + host + ":8080/upads-data-fabric" + "/ruleset", httpMethod, requestCallback, responseExtractor);

2 个答案:

答案 0 :(得分:10)

唐&#39;吨。将jquery mobile append does not work与适当的Resource方法结合使用。

使用HttpEntity作为Resource创建body。有RestTemplate#exchange来表示类路径资源。默认情况下,RestTemplate会注册一个ResourceHttpMessageConverter个流。

答案 1 :(得分:1)

除了@ sotirios-delimanolis答案外,您还需要为RestTemplate指定此设置,以便在内部将org.springframework.http.HttpOutputMessage识别为org.springframework.http.StreamingHttpOutputMessage,因为否则它会复制整个流到其内部流,因此您只需将其加载到内存中即可。这样,它将使用原始流的大块并将其发送。

HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setBufferRequestBody(false);
restTemplate.setRequestFactory(requestFactory);

我之所以这样说是因为StreamingHttpOutputMessage只有一个实现,而HttpComponentsClientHttpRequestFactory是创建它的唯一地方。

可复制的示例:

MultiValueMap<String, Object> bodyMap = new LinkedMultiValueMap<>();
UrlResource urlResource = new UrlResource(MY_EXTERNAL_FILE_URL) { //uses URL#inputStream
    @Override
    public String getFilename() {
        return FILE_NAME;
    }
};
bodyMap.add("file", urlResource); //other service uses -- @RequestParam("file") MultipartFile -- in its controller
RequestEntity<MultiValueMap<String, Object>> request =
    RequestEntity.post(URI.create("http://localhost:6666/api/file"))
        .contentType(MediaType.MULTIPART_FORM_DATA)
        .body(bodyMap);

//should be a @Bean
RestTemplate restTemplate = new RestTemplate ();
HttpComponentsClientHttpRequestFactory requestFactory = new 
HttpComponentsClientHttpRequestFactory();
requestFactory.setBufferRequestBody(false);
restTemplate.setRequestFactory(requestFactory);

System.out.println(restTemplate.exchange(request, FileMetadata.class));