簡體   English   中英

Spring RestTemplate 將響應流式傳輸到另一個請求中

[英]Spring RestTemplate streaming response into another request

我正在嘗試使用 spring 的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關閉,流不再可處理。

我希望能夠實現這個場景,而不必完全存放文件在內存中或將其寫入文件(如描述在這里)。

任何提示都非常感謝。

如果您想直接轉發響應而不將其保存在內存中,則必須直接寫入響應:

@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;
        });
}

由於您告訴 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)

編輯

正如 OP 所述,這仍會將文件加載到內存中。 InputStream 在幕后是一個 ByteArrayInputStream。

默認的 RestTemplate 和 MessageConverters 根本不是為流媒體內容制作的。 您可以編寫自己的org.springframework.web.client.ResponseExtractor實現,也可以編寫 MessageConverter。 在 ResponseExtractor 中,您可以訪問org.springframework.http.client.ClientHttpResponse

恕我直言,對於您的用例,您最好使用 Apache Httpcomponents HttpClient 在其中找到HttpEntity#writeTo(OutputStream)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM