java Spring RestTemplate 将响应流式传输到另一个请求中
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/41856005/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring RestTemplate streaming response into another request
提问by Mathias Dpunkt
I am trying to stream the result of a file download directly into another post using spring's RestTemplate
我正在尝试使用 spring 将文件下载的结果直接流式传输到另一篇文章中 RestTemplate
My current approach is the following:
我目前的方法如下:
ResponseEntity<InputStreamResource> downloadResponse = restTemplate.getForEntity(fileToDownloadUri, InputStreamResource.class);
InputStreamResource imageInputStreamResource = downloadResponse.getBody();
ResponseEntity<String> response = restTemplate.exchange(storageUri, POST, new HttpEntity<>(imageInputStreamResource), String.class);
However, I get the following exception running the code above:
但是,运行上面的代码时出现以下异常:
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)
It seems that the response is always closed as the final step of processing. With the response, the HttpURLConnection
is closed, and the stream is no longer processable.
似乎响应总是作为处理的最后一步关闭。随着响应,HttpURLConnection
关闭,并且流不再可处理。
I would like to be able to implement this scenario without having to hold the file completely in memory or writing it to a file (as described here).
我希望能够实现这个场景,而不必完全存放文件在内存中或将其写入文件(如描述在这里)。
Any hints are highly appreciated.
任何提示都非常感谢。
回答by user1978011
If you want to forward the response directly without ever holding it in memory, you have to directly write to the response:
如果您想直接转发响应而不将其保存在内存中,则必须直接写入响应:
@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;
});
}
回答by Redlab
Since you tell RestTemplate to expect InputStreamResource it will try and use an appropriate converter to convert your message to a InputStreamResource. ( I'm guessing there is none that handles this as you want )
由于您告诉 RestTemplate 期望 InputStreamResource,它会尝试使用适当的转换器将您的消息转换为 InputStreamResource。(我猜没有人可以按照您的意愿处理此问题)
You should be able to let it expect a Resource from where you can get an input stream and read that.
您应该能够让它期待一个资源,您可以从中获取输入流并读取它。
import org.springframework.core.io.Resource;
ResponseEntity<Resource> exchange = RestTemplate.exchange(url, HttpMethod.GET, new HttpEntity(httpHeaders), Resource.class);
InputStream inputStream = exchange.getBody().getInputStream();
using this you can write the response to somewhere else. Files.write(inputStream, new File("./test.json"));
wrote the file for me, so I assume the inputstream can also be used somewhere else. ( I used Spring 4.3.5 )
使用它,您可以将响应写入其他地方。Files.write(inputStream, new File("./test.json"));
为我编写了文件,所以我假设输入流也可以在其他地方使用。(我使用的是 Spring 4.3.5)
edit:
编辑:
As the OP states, this will still load the file in memory. Behind the scene the InputStream is a ByteArrayInputStream.
正如 OP 所述,这仍会将文件加载到内存中。InputStream 在幕后是一个 ByteArrayInputStream。
The default RestTemplate and MessageConverters are not made for streaming content at all.
You could write your own implementation of a org.springframework.web.client.ResponseExtractor
and maybe a MessageConverter. In ResponseExtractor you have access to the org.springframework.http.client.ClientHttpResponse
默认的 RestTemplate 和 MessageConverters 根本不是为流媒体内容制作的。您可以编写自己的 aorg.springframework.web.client.ResponseExtractor
或 MessageConverter 实现。在 ResponseExtractor 中,您可以访问org.springframework.http.client.ClientHttpResponse
imho for your use case, you might be better of using Apache Httpcomponents HttpClient where you find HttpEntity#writeTo(OutputStream)
.
恕我直言,对于您的用例,您最好在找到HttpEntity#writeTo(OutputStream)
.