我有一个servlet,允许用户从网页下载(可能很大)zip文件。如果用户单击链接以下载zip文件,则在servlet中执行类似以下的代码:
response.setContentType("application/zip");
response.setHeader("Content-disposition", "attachment; filename=foo.zip");
response.setHeader("Pragma", "");
response.setHeader("Cache-Control", "no-store");
ZipOutputStream out = new ZipOutputStream(response.getOutputStream());
// write entries to the zip file...
...
out.close()
但是,如果用户在下载开始后和完成之前刷新或导航离开页面(在Firefox 3.5.7中),则下载将失败。弹出以下错误:
C:\ blah \ foo.zip.part不可能 保存,因为源文件可以 不读。
稍后再试,或与服务器联系 管理员。
关于如何确保在这种情况下继续下载的任何想法?
更新:启动下载的链接是简单的vanilla链接。有趣的是,IE上的行为是不同的。似乎没有加载网站上其他地方的链接(从当前加载的屏幕)(浏览器状态栏显示“等待https://mysite/clicked_linky.do ...”),阻止直到下载完成。在地址栏中键入不同的URL或使用快捷方式/收藏夹链接导航离开页面,但下载按预期继续。只有Firefox似乎显示我上面描述的确切行为,尽管IE阻止不是最佳的。
答案 0 :(得分:6)
事实上这应该不会发生。下载计为单独的请求,该请求应在调用时独立于父页面在后台运行。你究竟是如何解雇下载请求的?通过简单的vanilla链接或链接(错误地)激发ajaxical请求来运行下载?
无论如何,您至少显然希望能够恢复下载。在这种情况下,您需要相应地在下载中至少发送Accept-Ranges
,ETag
和Last-Modified
响应标头。然后,客户端可以通过分别发送If-Range
和Range
请求标头以及您可以与RandomAccessFile
结合使用的指定字节范围来发送恢复下载来发送剩余字节。您可以在this article中找到更多信息和servlet示例。
这就是理论。在您的特定情况下,当您正在快速压缩文件时,它会有点琐碎。您需要先将zip写入服务器本地磁盘文件系统的临时文件夹,然后从中流式传输,最后在下载成功完成后删除文件 (即{{1没有抛出out.close()
)。您可以通过请求参数或pathinfo或会话中的密钥来识别关联的zip文件。
更新:根据您的更新:我真的不知道,我从未体验过它,但至少我可以告诉you're not the only one who suffered from this problem。至少,如前所述实现恢复功能可能是这个特定问题的解决方案,因为Firefox会自动恢复下载,而不会产生不完整的部分。
更新2 :在阅读完更新和浏览器行为后仔细考虑后,看起来在触发实际请求和响应标头到达之间存在相当大的时间差。我不知道你如何加载文件的确切细节,但它看起来就像收集ZIP文件需要花费时间(可能是你之前从网络文件系统或数据库加载它们) ?)并且您只在之后设置/发送响应标题,您已收集了所有ZIP文件。尝试设置标题并执行IOException
之前执行昂贵的任务。通过这种方式,浏览器将尽快获得标题,并且知道它可能会产生什么。
答案 1 :(得分:0)
我怀疑这是使用servlet的一个假象 - 可能是因为重新分配线程。当然,我用PHP编写的类似设置没有这样的问题(每个请求都由(有效的)新进程处理。
HTH
℃。