POST InputStream с RestTemplate

Имам клиент, който трябва да публикува голям брой големи json файлове на сървър. Успях да го накарам да работи, като прочетох всеки от файловете в паметта и публикувах целия файл с RestTemplate. Клиентът обаче бързо изчерпва паметта си за работа с големите json файлове. Искам да премина към стрийминг подход, но не мога да разбера как да използвам правилно FileInputStream с RestTemplate. Намерих този въпрос и използвах кода, даден в приетия отговор, но Все още виждам изключения за използване на паметта и 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);

person Tom    schedule 02.12.2015    source източник


Отговори (2)



В допълнение към отговора @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));
person Sam    schedule 26.07.2018
comment
Благодаря ти. HttpComponentsClientHttpRequestFactory, когато се добави към stackoverflow.com/a/52005690/1981358 изглежда е точно това, от което имах нужда. - person peater; 06.11.2019