浏览器收到文件下载时进行检测?

  • 回答 (2)
  • 关注 (0)
  • 查看 (270)

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

我以隐藏的形式发出请求,发送到服务器,并针对其隐藏的iframe的结果。这是所以我不会取代整个浏览器窗口的结果。我在iframe上侦听一个“加载”事件,希望在下载完成时触发。

我用文件返回一个“Content-Disposition:attachment”标题,导致浏览器显示“Save”对话框。但浏览器不会触发iframe中的“加载”事件。

我尝试的一种方法是使用多部分响应。所以它会发送一个空的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文件,触发“加载”事件,然后显示可下载文件的“保存”对话框。但是在IE和Safari上却失败了; IE浏览器会触发“加载”事件,但不会下载文件,Safari下载文件(名称和内容类型错误),并且不会触发“加载”事件。

一个不同的方法可能是打电话来启动文件创建,然后轮询服务器,直到它准备好,然后下载已经创建的文件。但我宁愿避免在服务器上创建临时文件。

有没有人有更好的主意?

头像是我媳妇头像是我媳妇提问于
心愿回答于

一个非常简单的(而且是蹩脚的)单行解决方案是使用window.onblur()事件关闭加载对话框。当然,如果时间太长,用户决定做其他事情(如阅读电子邮件),加载对话框将关闭。

Dust资深服务器虚拟化工程师。回答于

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

客户端算法:

生成一个随机的唯一标记。

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

显示“等待”指示符。

启动一个计时器,每隔一秒左右,寻找名为“fileDownloadToken”(或任何你决定的)的cookie。

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

服务器算法:

查找请求中的GET / POST字段。

如果它具有非空值,则删除一个cookie(例如“fileDownloadToken”),并将其值设置为该令牌的值。

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

$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
    );
}

所属标签

可能回答问题的人

  • 学生

    3 粉丝476 提问7 回答
  • uncle_light

    5 粉丝518 提问6 回答
  • 最爱开车啦

    8 粉丝503 提问5 回答
  • 骑牛看晨曦

    4 粉丝522 提问5 回答

扫码关注云+社区

领取腾讯云代金券