Detect when browser receives file download

前端 未结 22 1744
陌清茗
陌清茗 2020-11-21 04:55

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,

22条回答
  •  被撕碎了的回忆
    2020-11-21 05:46

    One possible solution uses JavaScript on the client.

    The client algorithm:

    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.

    The server algorithm:

    1. Look for the GET/POST field in the request.
    2. If it has a non-empty value, drop a cookie (e.g. "fileDownloadToken"), and set its value to the token's value.

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

    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();
    

    Where:

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

提交回复
热议问题