【问题标题】:Return a stream with Spring MVC's ResponseEntity返回带有 Spring MVC 的 ResponseEntity 的流
【发布时间】:2013-12-18 11:05:17
【问题描述】:

我有一个返回 ResponseEntity 的 Spring MVC 方法。根据检索到的具体数据,它有时需要向用户返回数据流。有时它会返回流以外的东西,有时还会返回重定向。我绝对希望这是一个流而不是字节数组,因为它可能很大。

目前,我使用以下 sn-p 代码返回流:

HttpHeaders httpHeaders = createHttpHeaders();
IOUtils.copy(inputStream, httpServletResponse.getOutputStream());

return new ResponseEntity(httpHeaders, HttpStatus.OK);

不幸的是,这不允许 Spring HttpHeaders 数据实际填充响应中的 HTTP 标头。这是有道理的,因为我的代码在 Spring 收到 ResponseEntity 之前写入了 OutputStream。

以某种方式返回 ResponseEntity 和 InputStream 并让 Spring 处理它会非常好。它还将与我可以成功返回ResponseEntity 的函数的其他路径平行。无论如何我可以用 Spring 完成这个吗?


另外,我确实尝试在 ResponseEntity 中返回 InputStream 只是为了看看 Spring 是否会接受它。

return new ResponseEntity(inputStream, httpHeaders, HttpStatus.OK);

但它会抛出这个异常:

org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation

我可以通过直接在HttpServletResponse 上设置所有内容来使我的功能正常工作,但我只想使用 Spring 来执行此操作。

【问题讨论】:

  • 我怀疑 Spring 不知道如何将 InputStream 主体转换为 AFAIK 的响应,默认情况下没有 HttpMessageConverter 可以与 InputStreams 一起使用。也许尝试注册一个与 InputStream 一起使用的自定义 HttpMessageConverter。 ByteArrayHttpMessageConverter 应该可以满足您的大部分需求。
  • 你试过@ResponseBody注解吗?
  • 我的 MVC 方法上确实有 @ResponseBody 注释。

标签: java spring servlets spring-mvc


【解决方案1】:

Spring 的InputStreamResource 运行良好。您需要手动设置 Content-Length,否则 Spring 似乎试图读取流以获取 Content-Length。

InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
httpHeaders.setContentLength(contentLengthOfStream);
return new ResponseEntity(inputStreamResource, httpHeaders, HttpStatus.OK);

我从未找到任何建议使用此类的网页。我只是猜到了,因为我注意到有一些关于使用 ByteArrayResource 的建议。

【讨论】:

  • 正确,默认情况下还注册了一个ResourceHttpMessageConverter,它知道如何处理org.springframework.core.io.Resource实例。所以将InputStream 包装在InputStreamResouce 中并返回它会起作用。
  • 我遇到了这个问题,使用这种方法,我可以用 64MB 堆流传输一个 500MB 的文件——它肯定是在缓冲输出,而不仅仅是分配一个字节数组。非常感谢 David V 的回答。剩下的唯一问题是:Spring 是否正确关闭了 InputStream 创建的任何其他资源?我一直试图通过谷歌搜索来解决这个问题,但我无法以一种或另一种方式找到任何信息。我认为 Spring 作者会采取措施避免此类代码导致资源泄漏,但我想确定。
  • @Nilesh,您确实需要自己的流程来确定contentLengthOfStream。否则 Spring 将打开流并读取它。这不适用于大型流或只能读取一次的流。
  • @SebastiaanvandenBroek,这将取决于您如何获取流。我们通常从 S3 读取,因此我们将 contentLengthOfStream 设置为 S3 SDK 提供的 Content-Length 的值。如果使用文件长度从文件加载,你也可以做类似的事情。
猜你喜欢
  • 2020-05-23
  • 1970-01-01
  • 2018-04-05
  • 2017-03-13
  • 2020-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多