我有一个允许用户下载动态生成文件的页面。生成它需要很长时间,所以我想显示一个“等待”指示器。问题是,我不知道如何检测浏览器何时接收到文件,以便我可以隐藏指示器。
我请求一个隐藏的表单,它post到服务器,并以一个隐藏的iframe作为其结果的目标。这样我就不会用结果替换整个浏览器窗口。我监听iframe上的“load”事件,希望它在下载完成时触发。
我将文件返回一个“Content-Disposition: attachment”头,这将导致浏览器显示“Save”对话框。但是浏览器不会在iframe中触发“load”事件。
我尝试过的一种方法是采用多部分回答。所以它会发送一个空的HTML文件,以及附加的可下载文件。
例如:
Content-type: multipart/x-mixed-replace;boundary="abcde"
--abcde
Content-type: text/html
--abcde
Content-type: application/vnd.fdf
Content-Disposition: attachment; filename=foo.fdf
file-content
--abcde
这在Firefox中是有效的;它接收空HTML文件,触发“load”事件,然后显示可下载文件的“Save”对话框。但它在ie和Safari浏览器上无法运行;Internet Explorer触发“load”事件,但它不下载文件,而Safari下载文件(带有错误的名称和内容类型),但不触发“load”事件。
另一种方法可能是调用启动文件创建,轮询服务器直到准备就绪,然后下载已经创建的文件。但我宁愿避免在服务器上创建临时文件。
我该怎么办?
我使用以下代码下载blobs并在下载后撤销对象URL。它在Chrome和Firefox中工作!
function download(blob){
var url = URL.createObjectURL(blob);
console.log('create ' + url);
window.addEventListener('focus', window_focus, false);
function window_focus(){
window.removeEventListener('focus', window_focus, false);
URL.revokeObjectURL(url);
console.log('revoke ' + url);
}
location.href = url;
}
关闭文件下载对话框后,窗口将获得其焦点,因此将触发焦点事件。
如果您正在流式处理动态生成的文件,并且还实现了实时的服务器到客户端消息库,那么您可以非常容易地提醒客户端。
The server-to-client messaging library I like and recommend is Socket.io (via Node.js). After your server script is done generating the file that is being streamed for download your last line in that script can emit a message to Socket.io which sends a notification to the client. On the client, Socket.io listens for incoming messages emitted from the server and allows you to act on them. The benefit of using this method over others is that you are able to detect a "true" finish event after the streaming is done.
例如,您可以在单击下载链接后显示繁忙指示器,流式传输文件,向Socket发出消息。在您的流脚本的最后一行中,从服务器中输入io,在客户端侦听通知,接收通知并通过隐藏busy指示器更新您的UI。
我知道大多数读到这个问题答案的人可能没有这种类型的设置,但我已经在我自己的项目中使用了这种确切的解决方案,而且效果非常好。
套接字。IO非常容易安装和使用。查看更多信息:http://socket.io/
当按钮/链接被单击时创建一个iframe,并将其附加到body。
$('<iframe />')
.attr('src', url)
.attr('id', 'iframe_download_report')
.hide()
.appendTo('body');
创建一个延迟的iframe,下载后删除。
var triggerDelay = 100;
var cleaningDelay = 20000;
var that = this;
setTimeout(function() {
var frame = $('<iframe style="width:1px; height:1px;" class="multi-download-frame"></iframe>');
frame.attr('src', url + "?" + "Content-Disposition: attachment ; filename=" + that.model.get('fileName'));
$(ev.target).after(frame);
setTimeout(function() {
frame.remove();
}, cleaningDelay);
}, triggerDelay);