2017-01-25 3 views
3

Я пытаюсь транслировать результат загрузку файла непосредственно в другой пост, используя RestTemplateSpring RestTemplate ответ потокового в другой запрос

Мой нынешний подход весенний заключается в следующем:

ResponseEntity<InputStreamResource> downloadResponse = restTemplate.getForEntity(fileToDownloadUri, InputStreamResource.class); 

    InputStreamResource imageInputStreamResource = downloadResponse.getBody(); 

    ResponseEntity<String> response = restTemplate.exchange(storageUri, POST, new HttpEntity<>(imageInputStreamResource), String.class); 

Однако, я получаю следующее исключение:

org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://host:port/path/some.jpg": stream is closed; nested exception is java.io.IOException: stream is closed 

    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:6 
... 
Caused by: java.io.IOException: stream is closed 
    at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.ensureOpen(HttpURLConnection.java:3348) 
    at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3373) 

Похоже, что ответ всегда закрыт как последний шаг обработки. С ответом HttpURLConnection закрывается, и поток больше не обрабатывается.

Я хотел был бы иметь возможность осуществить этот сценарий без того, чтобы держать файл полностью в памяти или записать его в файл (как описано here).

Любые советы приветствуются.

+0

возможно тождественное решение здесь http://stackoverflow.com/questions/15781885/ how-to-forward-large-files-with-resttemplate – Redlab

+0

@Redlab там это 'FileSystemResource' - это сработало бы - моя проблема в том, что' InputStream' закрывается после завершения запроса 'GET'. Поэтому я не могу использовать его дальше. –

ответ

0

Поскольку вы скажете RestTemplate ожидать InputStreamResource, он попытается использовать соответствующий конвертер для преобразования вашего сообщения в InputStreamResource. (Я предполагаю, что нет такого, который обрабатывает это, как вы хотите)

Вы должны быть в состоянии позволить ему ожидать Ресурс, откуда вы можете получить поток ввода и прочитать это.

import org.springframework.core.io.Resource; 

ResponseEntity<Resource> exchange = RestTemplate.exchange(url, HttpMethod.GET, new HttpEntity(httpHeaders), Resource.class); 
InputStream inputStream = exchange.getBody().getInputStream(); 

Используя этот код, вы можете написать ответ на сообщение в другом месте. Files.write(inputStream, new File("./test.json")); написал файл для меня, поэтому я предполагаю, что входной поток также можно использовать где-то в другом месте. (Я использовал Spring 4.3.5)

редактировать:

Как О.П. государств, то это все равно будет загружать файл в память. За сценой InputStream является ByteArrayInputStream.

По умолчанию RestTemplate и MessageConverters не созданы для потоковой передачи контента вообще. Вы можете написать собственную реализацию org.springframework.web.client.ResponseExtractor и, возможно, MessageConverter. В ResponseExtractor у вас есть доступ к org.springframework.http.client.ClientHttpResponse

imho для вашего использования, возможно, вам лучше использовать Apache Httpcomponents HttpClient, где вы найдете HttpEntity#writeTo(OutputStream).

+0

Я боюсь, что этого не делаю - это именно то, что я делаю - 'ResponseEntity downloadResponse = restTemplate.getForEntity (fileToDownloadUri, InputStreamResource.class) ;, но inputStream закрывается уже после вызова. Вы пробовали использовать InputStream в своем коде выше? –

+0

Вы правы, я ошибаюсь String и InputStreamResource (исправит ответ). Но, тем не менее, используйте org.springframework.core.io.Ресурс вместо InputStreamResource – Redlab

+0

Спасибо за ввод - если я заставлю его вернуть ресурс, то 'getForEntity' возвращает' ByteArrayResource'. Поэтому я загружаю полный файл в память. Который я бы хотел избежать - вот почему я попробовал «InputStreamResource». Я хочу передать ответ в тело сообщения. –

4

Если вы хотите отправить ответ непосредственно никогда не держа его в памяти, вы должны написать непосредственно в ответ:

@RequestMapping(value = "/yourEndPoint") 
public void processRequest(HttpServletResponse response) { 
    RestTemplate restTemplate = new RestTemplate(); 

    response.setStatus(HttpStatus.OK.value()); 

    restTemplate.execute(
     fileToDownloadUri, 
     HttpMethod.GET, 
     (ClientHttpRequest requestCallback) -> {}, 
     responseExtractor -> { 
      IOUtils.copy(responseExtractor.getBody(), response.getOutputStream()); 
      return null; 
     }); 
} 
Смежные вопросы