简而言之,我有一个 Servlet ,可以检索图片/视频。来自底层数据存储。
为了存档,我需要将文件 InputStream 复制到 ServletResponce * OutputStream *
从我的观点来看,这是无效的,因为我需要在发送之前将文件复制到内存中,指定 InputStream 会更方便, OutputStream 会在读取缓冲区中的一些数据后读取数据并立即发送。
我查看了 ServletResponce 文档,它有一些缓冲区用于消息数据,所以我有几个问题。
这是正确的机制吗? 如果我决定在Servlet处理结束时不发送文件怎么办? 例如: 如果我在 OutputStream 中复制 InputStream ,然后发现这不是授权请求,并且用户无权查看此对象(设计中的错误可能)我会仍然会向客户端发送一些数据,虽然这不是我想要的或不是。
答案 0 :(得分:1)
要解决您的第一个问题,您可以使用来自Apache Commons Lang的IOUtils
轻松地将InputStream
复制到OutputStream
:
IOUtils.copy(fileInputStream, servletOutputStream);
它使用4K缓冲区,因此不应该关注内存消耗。实际上,您不能直接从InputStream
发送 数据。在最低级别,操作系统仍然必须将文件内容读取到某个内存位置,并且为了将其发送到套接字,您需要提供要发送的数据所在的内存位置。 Streams只是一个有用的抽象。
关于你的第二个问题:这是HTTP的工作方式:如果你开始将数据流传输到客户端,servlet容器首先发送所有响应头。如果你在中间中止,从客户端的角度看,它看起来像是中断下载。
答案 1 :(得分:0)
这是正确的机制吗?
基本上,它是Servlet APIs
提供的唯一机制。您需要考虑到这一点来设计您的servlet。
(很难看出如何以其他方式完成。read
系统调用从设备(磁盘)将数据读入内存。write
系统调用将数据从内存写入设备(网络接口)。没有系统调用将数据直接从一个设备传输到另一个设备。您可以做的最好是减少应用程序中数据的复制量。如果您使用IOUtils.copy
之类的东西,它应该尽可能地减少它。唯一可以避免通过应用程序内存的方法是使用一些针对内容交付优化的专用硬件/操作系统组合。 )
然而,无论如何,这可能都没有实际意义。在大多数情况下,性能瓶颈可能是通过网络传输数据。数据可能从磁盘到内存读取,复制和写入网络接口的速度比通过网络移动到用户的Web浏览器(或其他任何)的速度快几个数量级。
如果它没有实际意义,那么进行内容交付的一种实用方法是使用以本机代码实现的单独Web服务器,我们优化这些服务器以提供静态内容;例如类似于nginx
。)
如果我决定在
Servlet
处理结束时不发送文件,该怎么办?例如:如果我在InputStream
中复制了OutputStream
,然后发现这不是授权请求,并且用户无权查看此对象(设计中的错误可能),我仍会发送一些数据给客户,虽然这不是我想要的或不是。
在将内容读入内存之前,您应该编写servlet来进行访问检查。理想情况下,在你"承诺"通过发送响应头来响应。