当前位置:  开发笔记 > 编程语言 > 正文

流式传输java servlet中的大型文件

如何解决《流式传输javaservlet中的大型文件》经验,为你挑选了3个好方法。

我正在构建一个需要扩展的java服务器.其中一个servlet将提供存储在Amazon S3中的图像.

最近在加载时,我的虚拟机内存耗尽了,之后我添加了代码来提供图像,所以我很确定流式传输更大的servlet响应会导致我的麻烦.

我的问题是:在从数据库或其他云存储中读取时,如何编写java servlet以将大型(> 200k)响应流回浏览器,是否有任何最佳实践?

我已经考虑将文件写入本地临时驱动器,然后生成另一个线程来处理流,以便可以重用tomcat servlet线程.这似乎很重要.

任何想法将不胜感激.谢谢.



1> John Vasilef..:

如果可能,您不应存储要在内存中提供的文件的全部内容.相反,为数据获取InputStream,并将数据复制到Servlet OutputStream中.例如:

ServletOutputStream out = response.getOutputStream();
InputStream in = [ code to get source input stream ];
String mimeType = [ code to get mimetype of data to be served ];
byte[] bytes = new byte[FILEBUFFERSIZE];
int bytesRead;

response.setContentType(mimeType);

while ((bytesRead = in.read(bytes)) != -1) {
    out.write(bytes, 0, bytesRead);
}

// do the following in a finally block:
in.close();
out.close();

我同意toby,你应该"将它们指向S3网址".

至于OOM例外,你确定它与提供图像数据有关吗?假设你的JVM有256MB的"额外"内存用于提供图像数据.在Google的帮助下,"256MB/200KB"= 1310.对于2GB"额外"内存(这些天非常合理的数量),可以支持超过10,000个并发客户端.即便如此,1300个同步客户端数量也相当大.这是您遇到的负载类型吗?如果没有,您可能需要查看其他地方的OOM异常原因.

编辑 - 关于:

在这个用例中,图像可以包含敏感数据......

几周前,当我阅读S3文档时,我注意到您可以生成可以附加到S3 URL的时间过期密钥.因此,您不必向公众开放S3上的文件.我对该技术的理解是:

    初始HTML页面包含指向您的webapp的下载链接

    用户点击下载链接

    您的webapp会生成一个S3 URL,其中包含一个过期的密钥,比如5分钟.

    使用步骤3中的URL将HTTP重定向发送到客户端.

    用户从S3下载文件.即使下载时间超过5分钟,这仍然有效 - 一旦下载开始,它可以继续完成.


彼得,如果您不能直接将用户指向云服务URL,并且您想要设置内容长度标头,并且您还不知道大小,并且无法查询云服务的大小,那我想您最好最好首先将数据流传输到服务器上的临时文件。当然,在将第一个字节发送给客户端之前在服务器上保存副本可能会导致用户认为请求失败,具体取决于云->服务器传输需要多长时间。

2> airportyh..:

你为什么不把它们指向S3网址?从S3获取一个工件,然后通过您自己的服务器将其流式传输给我,这就失去了使用S3的目的,即卸载带宽和处理将图像提供给亚马逊的过程.



3> blast_hardch..:

我已经看到很多代码,比如john-vasilef(当前接受的)答案,一个紧密的while循环从一个流中读取块并将它们写入另一个流.

我所提出的论点是反对不必要的代码重复,支持使用Apache的IOUtils.如果您已经在其他地方使用它,或者您正在使用的其他库或框架已经依赖它,那么它就是一条已知且经过充分测试的单行.

在下面的代码中,我将一个对象从Amazon S3流式传输到servlet中的客户端.

import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.io.IOUtils;

InputStream in = null;
OutputStream out = null;

try {
    in = object.getObjectContent();
    out = response.getOutputStream();
    IOUtils.copy(in, out);
} finally {
    IOUtils.closeQuietly(in);
    IOUtils.closeQuietly(out);
}

6条明确定义的模式与适当的流关闭看起来非常稳固.

推荐阅读
mobiledu2402852357
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有