当前位置: 首页 > 知识库问答 >
问题:

Spring Rest将流响应模板化为另一个请求

文志学
2023-03-14

我正在尝试使用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关闭,流不再可处理。

我希望能够实现这个场景,而不必将文件完全保存在内存中或将其写入文件(如此处所述)。

非常感谢任何提示。

共有2个答案

韦欣德
2023-03-14

因为您告诉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根本不是为流内容而设计的。您可以编写自己的< code > org . spring framework . web . client . response extractor 和MessageConverter的实现。在ResponseExtractor中,您可以访问< code > org . spring framework . http . client . clienthttpresponse

对于您的用例,最好使用Apache Httpcomponents HttpClient,在那里可以找到HttpEntity#writeTo(OutputStream)

堵鸿光
2023-03-14

如果要直接转发响应而不将其保存在内存中,则必须直接写入响应:

@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;
        });
}
 类似资料:
  • 问题内容: 我有一个非常基本的模板(basic_template.html),并希望使用使用另一部分模板格式化的数据来填写。basic_template.html可能包含使用部分模板格式化的几件事。 我应该如何在views.py中构建代码? 我这样做的原因是稍后将使用Ajax填充。我这样做对吗? 问题答案: 你可以做: 另一个Django模板在哪里。在这里,你可以放入将用Ajax获得的HTML。

  • 我有一个XML,我必须循环测试结果和组件。当组件的类型与特定名称匹配时,我必须对该组件应用不同的模板。我为每种组件类型创建了一个XSL-to,具有不同的模板,例如:NORMALTEXTBOX。但是这些模板并没有被应用到组件块中。。。谁能帮我一下吗? XML XSL

  • 应用程序应异步(在单独的线程中)记录以下信息,而不会影响客户端。 请求HTTP方法和URI 如果我们在过滤器中使用,那么spring将无法再次使用它进行json到对象的映射。在输入流到对象映射期间的某个地方,我们可以插入记录器吗? 更新: 我们可以在MessageConverter中编写日志代码,但这似乎不是一个好主意。

  • 我正在尝试调试我的<代码>。htaccess文件,其中包含: 在反复访问Safari中看到的同一网页时: 名称 = 包装.html, 方法 = GET, 状态 = 200 (正常), 类型 = 文本/html 名称=应用.html,方法=GET,状态=200(正常),类型=应用/x冲击波闪存 Chrome: 名称=包装器。html,方法=GET,状态=304(未修改),类型=text/html 名

  • 问题内容: 有没有一种方法可以将Flask请求对象注入到其他Flask应用中。这就是我想要做的: 我正在尝试使用Google Cloud Functions,这是由云运行时调用的函数。它接收一个作为参数,然后我要通过自己的一组路由进行处理。 我尝试了以下操作,但不起作用: 对于所有请求,这将返回404错误。 编辑: 实现的简单方法如下: 这本质上要求我自己编写路由匹配逻辑。我想知道是否有一种避免这

  • 我有以下xml文件结构: 我的目标是借助xslt文件生成html输出。在这样做的过程中,我想应用一个模板来指导根元素的子元素,该元素将标记的名称输出为标题1,其内容包含在 为了更容易理解我想要的是HTML输出的示例: 现在,我的尝试如下所示:http://pastebin.com/wKgSLbcE 但它不适用于