使用 RestTemplate 获取 InputStream

新手上路,请多包涵

我正在使用 URL 类从中读取 InputStream。有什么办法可以为此使用 RestTemplate 吗?

 InputStream input = new URL(url).openStream();
JsonReader reader = new JsonReader(new InputStreamReader(input, StandardCharsets.UTF_8.displayName()));

我怎样才能得到 InputStreamRestTemplate 而不是使用 URL

原文由 user1950349 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.3k
2 个回答

您不应该直接获取 InputStreamRestTemplate 用于封装处理响应(和请求)内容。它的优势在于处理所有 IO 并为您提供一个随时可用的 Java 对象。

其中一位 RestTemplate 的原作者 Brian Clozel 指出

RestTemplate 并不意味着流式传输响应主体;它的合同不允许这样做,而且它已经存在了很长时间,以至于在不中断许多应用程序的情况下无法改变其行为的这样一个基本部分。

您需要注册适当的 HttpMessageConverter 对象。这些将可以通过 HttpInputMessage 对象访问响应的 InputStream

As Abdull suggests , Spring does come with an HttpMessageConverter implementation for Resource which itself wraps an InputStream , ResourceHttpMessageConverter .它不支持所有 Resource 类型,但由于无论如何你都应该对接口进行编程,你应该只使用超级接口 Resource

当前的实现 (4.3.5) 将返回一个 ByteArrayResource 并将响应流的内容复制到一个新的 ByteArrayInputStream 您可以访问它。

您不必关闭流。 RestTemplate 会为您处理。 (不幸的是,如果您尝试使用 InputStreamResource ,另一种由 ResourceHttpMessageConverter 支持的类型,因为它包装了底层响应的 InputStream 暴露给您的客户端代码。)

原文由 Sotirios Delimanolis 发布,翻译遵循 CC BY-SA 4.0 许可协议

之前的回答都没有错,只是没有深入到我喜欢看到的深度。在某些情况下,处理低级别 InputStream 不仅是可取的,而且是必要的,最常见的示例是将大文件从源(某些 Web 服务器)流式传输到目标(数据库)。如果您尝试使用 ByteArrayInputStream ,那么您将收到 OutOfMemoryError 的欢迎也就不足为奇了。是的,您可以推出自己的 HTTP 客户端代码,但您必须处理错误的响应代码、响应转换器等。如果您已经在使用 Spring,寻找 RestTemplate 是一个自然的选择。

As of this writing, spring-web:5.0.2.RELEASE has a ResourceHttpMessageConverter that has a boolean supportsReadStreaming , which if set, and the response type is InputStreamResource , returns InputStreamResource ;否则返回 ByteArrayResource 。很明显,您不是唯一一个要求流媒体支持的人。

但是,存在一个问题: RestTemplateHttpMessageConverter 运行后不久关闭响应。因此,即使您请求了 InputStreamResource 并得到了它,也没有用,因为响应流已关闭。我认为这是他们忽略的设计缺陷;它应该取决于响应类型。所以不幸的是,为了阅读,你必须充分消耗反应;如果使用 RestTemplate 则不能传递它。

不过写是没问题的。如果您想流式传输 InputStreamResourceHttpMessageConverter 将为您完成。在引擎盖下,它使用 org.springframework.util.StreamUtils 一次写入 4096 个字节,从 InputStreamOutputStream

一些 HttpMessageConverter 支持所有媒体类型,因此根据您的要求,您可能必须从 RestTemplate 中删除默认媒体类型,并设置您需要的媒体类型,注意它们的相对订购。

最后但并非最不重要的是, ClientHttpRequestFactory 的实现有一个 boolean bufferRequestBody 你可以而且应该设置为 false 如果你正在上传一个大的流媒体。否则,您知道 OutOfMemoryError 。在撰写本文时, SimpleClientHttpRequestFactory (JDK 客户端)和 HttpComponentsClientHttpRequestFactory (Apache HTTP 客户端)支持此功能,但不支持 OkHttp3ClientHttpRequestFactory .再次,设计监督。

编辑:归档票证 SPR-16885

原文由 Abhijit Sarkar 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题