【问题标题】:Specify InputStream for ServletResponce instead of copying InputStream in OutputStream为 ServletResponce 指定 InputStream 而不是在 OutputStream 中复制 InputStream
【发布时间】:2012-03-29 19:22:42
【问题描述】:

简而言之,我有一个 Servlet,它可以检索图片/视频等。来自底层数据存储。

为了存档,我需要将文件 InputStream 复制到 ServletResponce *OutputStream*

在我看来这并不有效,因为我需要在发送之前将文件复制到内存中,因此指定 InputStream 会更方便,其中 OutputStream 会在读取缓冲区中的一些数据后立即读取数据并发送。

我查看了 ServletResponce 文档,它有一些用于消息数据的缓冲区,所以我有一些关于它的问题。

这是正确的机制吗? 如果我决定在 Servlet 处理结束时不发送文件怎么办? 例如: 如果我在OutputStream中复制了InputStream,然后发现这不是授权请求,并且用户无权查看此对象(可能是设计错误)我会仍然向客户端发送一些数据,尽管这不是我想要的,或者不是。

【问题讨论】:

    标签: java servlets inputstream outputstream


    【解决方案1】:

    为了解决您的第一个问题,您可以使用来自 Apache Commons Lang 的 IOUtils 轻松地将 InputStream 复制到 OutputStream

    IOUtils.copy(fileInputStream, servletOutputStream);
    

    它使用 4K 缓冲区,因此不必担心内存消耗。事实上,您不能立即InputStream 发送数据。在最低级别,操作系统仍然必须将文件内容读取到某个内存位置,并且为了将其发送到套接字,您需要提供要发送的数据所在的内存位置。流只是一个有用的抽象。

    关于您的第二个问题:HTTP 是这样工作的:如果您开始将数据流式传输到客户端,则 servlet 容器首先发送所有响应标头。如果您在中间中止,从客户端的角度来看,它看起来像是下载中断。

    【讨论】:

    • 我已经在使用 IOUtils.copy 进行处理了,这可能容易出错。 4K 缓冲区是 IOUtils 缓冲区的默认大小,因此使用另一个缓冲区进行 Servlet 处理不会那么有效。如果我想发送 8K 数据报,我要么需要使用 IOUtils 读取两次,要么添加可配置的复制实现。
    【解决方案2】:

    这是正确的机制吗?

    基本上,它是Servlet APIs提供的唯一机制。您需要考虑到这一点来设计您的 servlet。

    (很难看到它可以以其他方式完成。read 系统调用将数据从设备(磁盘)读取到内存中。write 系统调用从内存到设备(网络接口)。没有系统调用可以将数据直接从一个设备传输到另一个设备。您可以做的最好的事情是减少在应用程序中复制数据的数量。如果您使用 IOUtils.copy 之类的东西,它应该尽可能地减少它。避免经历应用程序记忆的唯一方法是使用一些针对内容交付优化的专用硬件/操作系统组合。)

    但是,无论如何,这可能没有实际意义。在大多数情况下,性能瓶颈很可能是网络上的数据移动。数据从磁盘读取到内存、复制和写入网络接口的速度可能比通过网络移动到用户的 Web 浏览器(或其他任何东西)要快几个数量级。

    如果它没有实际意义,那么进行内容交付的一种实用方法是使用一个单独的 Web 服务器,该服务器以我们为交付静态内容而优化的本机代码实现;例如类似nginx。)

    如果我决定在Servlet 处理结束时不发送文件怎么办?例如:如果我在OutputStream中复制了InputStream,然后发现这不是授权请求,用户无权看到这个对象(可能设计错误)我仍然会向客户端发送一些数据,虽然这不是我想要的,或者不是。

    您应该在将内容读入内存之前编写您的 servlet 来进行访问检查。理想情况下,在您通过发送响应标头“提交”响应之前。

    【讨论】:

      猜你喜欢
      • 2018-07-19
      • 2021-07-10
      • 2011-01-06
      • 2018-02-25
      • 2012-08-03
      • 2017-12-14
      • 2017-01-17
      • 1970-01-01
      相关资源
      最近更新 更多