【问题标题】: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

以某种方式返回 ResponseEntityInputStream 并让 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
相关资源
最近更新 更多