Java Servlets:当用户离开页面时,文件下载中断

Jef*_*eff 5 java servlets http download

我有一个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()
Run Code Online (Sandbox Code Playgroud)

但是,如果用户在下载开始后和完成之前刷新或导航离开页面(在Firefox 3.5.7中),则下载将失败.弹出以下错误:

无法保存C:\ blah\foo.zip.part,因为无法读取源文件.

请稍后重试,或与服务器管理员联系.

关于如何确保在这种情况下继续下载的任何想法?

更新:启动下载的链接是一个简单的vanilla链接.有趣的是,IE上的行为是不同的.似乎没有加载网站上其他位置的链接(从当前加载的屏幕)(浏览器状态栏显示"正在等待https://mysite/clicked_linky.do ..."),阻塞直到下载完成.在地址栏中键入不同的URL或使用快捷方式/收藏夹链接导航离开页面,但下载按预期继续.只有Firefox似乎显示我上面描述的确切行为,尽管IE阻止不是最佳的.

Bal*_*usC 6

事实上这应该不会发生.下载计为一个单独的请求,应该在调用时独立于父页面在后台运行.你究竟是如何解雇下载请求的?通过简单的vanilla链接或链接(错误地)触发ajaxical请求来运行下载?

无论如何,您至少显然希望能够恢复下载.在这种情况下,你至少需要发送Accept-Ranges,ETagLast-Modified沿下载相应的响应头.然后,客户可以要求通过发送继续下载If-Range,并Range分别与文件标识符,并且你可以结合使用与指定字节范围请求头RandomAccessFile发送剩余的字节.您可以在本文中找到更多信息和servlet示例.

这就是理论.在您的特定情况下,当您正在快速压缩文件时,它会有点琐碎.您需要先将zip写入服务器本地磁盘文件系统的临时文件夹,然后从中流式传输,最后只有在下载成功完成后才删除该文件(即out.close()没有丢弃IOException).您可以通过请求参数或pathinfo或会话中的密钥来识别关联的zip文件.

更新:根据您的更新:老实说我不知道​​,我从来没有经历过,但至少我可以告诉你,你不是唯一一个遭受这个问题的人.至少,如前所述实现恢复功能可能是这个特定问题的解决方案,因为Firefox会自动恢复下载而不会对不完整的部分产生影响.

更新2:在阅读完更新和浏览器行为后仔细考虑后,看起来在触发实际请求和响应标头到达之间存在相当大的时间差.我不知道你如何加载文件的确切细节,但看起来收集ZIP文件有时间成本(可能你是事先从网络文件系统或数据库加载它们?)并且你设置/只有收集了所有ZIP文件后才发送响应头.尝试设置标题并output.flush() 执行昂贵的任务之前执行操作.通过这种方式,浏览器将尽快获得标题,并且它将知道它可能期望的内容.