检测浏览器何时收到文件下载 [英] Detect when browser receives file download

查看:129
本文介绍了检测浏览器何时收到文件下载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个页面,允许用户下载动态生成的文件。生成需要很长时间,所以我想显示一个等待指标。问题是,我无法弄清楚如何检测浏览器何时收到文件,因此我可以隐藏指示器。

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 I can hide the indicator.

我正在提出请求一个隐藏的表单,POST到服务器,并为其结果定位隐藏的iframe。这样我就不会用结果替换整个浏览器窗口。我在iframe上收听加载事件,希望在下载完成后它会触发。

I'm making the request in 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, in the hope 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.

我尝试过的一种方法是使用多部分响应。因此它会发送一个空的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. For example:

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文件,触发加载事件,然后显示可下载文件的保存对话框。但它在IE和Safari上失败了; IE触发加载事件但不下载文件,Safari下载文件(名称和内容类型错误),并且不会触发加载事件。

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 make a 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?

推荐答案

一个可能的解决方案在客户端上使用JavaScript。

One possible solution uses JavaScript on the client.

客户端算法:


  1. 生成随机唯一令牌。

  2. 提交下载请求,并将令牌包含在GET / POST字段中。

  3. 显示等待指示符。

  4. 启动计时器,每隔一秒左右,查找名为fileDownloadToken的cookie(或您决定的任何内容)。

  5. 如果cookie存在且其值与令牌匹配,则隐藏等待指示符。

  1. Generate a random unique token.
  2. Submit the download request, and include the token in a GET/POST field.
  3. Show the "waiting" indicator.
  4. Start a timer, and every second or so, look for a cookie named "fileDownloadToken" (or whatever you decide).
  5. If the cookie exists, and its value matches the token, hide the "waiting" indicator.

服务器算法:


  1. 在请求中查找GET / POST字段。

  2. 如果有非空值,删除cookie(例如fileDownloadToken)和s以及它对令牌价值的价值。






客户端源代码(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
    );
}

这篇关于检测浏览器何时收到文件下载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆