问题描述
我有一个页面,允许用户下载动态生成的文件.生成需要很长时间,所以我想表现一个等待"指标.问题是,我不知道如何检测浏览器何时收到文件,以便我可以隐藏指示器.
I have a page that allows the user to download a dynamically-generated file. It takes a long time to generate, so I'd like to show a "waiting" indicator. The problem is, I can't figure out how to detect when the browser has received the file so that I can hide the indicator.
我正在请求一个隐藏的表单,该表单向服务器发送 POST 请求,并将其结果定位到一个隐藏的 iframe.这是,所以我不会用结果替换整个浏览器窗口.我听一个负载"iframe 上的事件,希望它会在下载完成后触发.
I'm requesting a hidden form, which POSTs to the server, and targets a hidden iframe for its results. This is, so I don't replace the entire browser window with the result. I listen for a "load" event on the iframe, hoping that it will fire when the download is complete.
我返回一个Content-Disposition:attachment
";文件头,这会导致浏览器显示保存"对话.但是浏览器不会触发加载"iframe 中的事件.
I return a "Content-Disposition: attachment
" header with the file, which causes the browser to show the "Save" dialog. But the browser doesn't fire a "load" event in the iframe.
我尝试过的一种方法是使用 multi-part
响应.所以它会发送一个空的 HTML 文件,以及附加的可下载文件.
One approach I tried is using a multi-part
response. So it would send an empty HTML file, as well as the attached downloadable file.
例如:
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 上失败;IE 触发加载"事件但不下载文件,并且 Safari 下载
文件(使用错误的名称和内容类型)并且不会触发 load"
事件.
This works in Firefox; it receives the empty HTML file, fires the "load"
event, then shows the "Save"
dialog for the downloadable file. But it fails on IE and Safari; IE fires the "load" event but doesn't download the file, and Safari downloads
the file (with the wrong name and content-type) and doesn't fire the "load"
event.
另一种方法可能是调用以开始文件创建,然后轮询服务器直到它准备好,然后下载已经创建的文件.但我宁愿避免在服务器上创建临时文件.
A different approach might be to call to start the file creation, then poll the server until it's ready, then download the already-created file. But I'd rather avoid creating temporary files on the server.
有没有人有更好的主意?
Does anyone have a better idea?
推荐答案
One 可能的解决方案 在客户端使用 JavaScript.
One possible solution uses JavaScript on the client.
客户端算法:
- 生成一个随机的唯一令牌.
- 提交下载请求,并将令牌包含在 GET/POST 字段中.
- 显示等待"指示器.
- 启动一个计时器,每隔一秒左右,查找一个名为fileDownloadToken"(或您决定的任何内容)的 cookie.
- 如果 cookie 存在,并且其值与令牌匹配,则隐藏等待"指示器.
服务器算法:
- 在请求中查找 GET/POST 字段.
- 如果它具有非空值,则删除 cookie(例如fileDownloadToken"),并将其值设置为令牌的值.
客户端源代码 (JavaScript):
Client source code (JavaScript):
function getCookie( name ) {
var parts = document.cookie.split(name + "=");
if (parts.length == 2) return parts.pop().split(";").shift();
}
function expireCookie( cName ) {
document.cookie =
encodeURIComponent(cName) + "=deleted; expires=" + new Date( 0 ).toUTCString();
}
function setCursor( docStyle, buttonStyle ) {
document.getElementById( "doc" ).style.cursor = docStyle;
document.getElementById( "button-id" ).style.cursor = buttonStyle;
}
function setFormToken() {
var downloadToken = new Date().getTime();
document.getElementById( "downloadToken" ).value = downloadToken;
return downloadToken;
}
var downloadTimer;
var attempts = 30;
// Prevents double-submits by waiting for a cookie from the server.
function blockResubmit() {
var downloadToken = setFormToken();
setCursor( "wait", "wait" );
downloadTimer = window.setInterval( function() {
var token = getCookie( "downloadToken" );
if( (token == downloadToken) || (attempts == 0) ) {
unblockSubmit();
}
attempts--;
}, 1000 );
}
function unblockSubmit() {
setCursor( "auto", "pointer" );
window.clearInterval( downloadTimer );
expireCookie( "downloadToken" );
attempts = 30;
}
示例服务器代码 (PHP):
Example server code (PHP):
$TOKEN = "downloadToken";
// Sets a cookie so that when the download begins the browser can
// unblock the submit button (thus helping to prevent multiple clicks).
// The false parameter allows the cookie to be exposed to JavaScript.
$this->setCookieToken( $TOKEN, $_GET[ $TOKEN ], false );
$result = $this->sendFile();
地点:
public function setCookieToken(
$cookieName, $cookieValue, $httpOnly = true, $secure = false ) {
// See: http://stackoverflow.com/a/1459794/59087
// See: http://shiflett.org/blog/2006/mar/server-name-versus-http-host
// See: http://stackoverflow.com/a/3290474/59087
setcookie(
$cookieName,
$cookieValue,
2147483647, // expires January 1, 2038
"/", // your path
$_SERVER["HTTP_HOST"], // your domain
$secure, // Use true over HTTPS
$httpOnly // Set true for $AUTH_COOKIE_NAME
);
}
这篇关于检测浏览器何时接收文件下载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!