it-swarm.com.de

Ermitteln, wann der Browser den Dateidownload empfängt

Ich habe eine Seite, auf der der Benutzer eine dynamisch generierte Datei herunterladen kann. Das Generieren dauert sehr lange, daher möchte ich eine Warteanzeige anzeigen. Das Problem ist, dass ich nicht herausfinden kann, wann der Browser die Datei erhalten hat, sodass ich die Anzeige ausblenden kann.

Ich stelle die Anfrage in einer verborgenen Form, die an den Server gesendet wird und deren Ergebnisse auf einen verborgenen Iframe abzielt. Dadurch ersetze ich nicht das gesamte Browserfenster mit dem Ergebnis. Ich warte auf ein "load" -Ereignis im iframe, in der Hoffnung, dass es ausgelöst wird, wenn der Download abgeschlossen ist.

Ich gebe einen "Content-Disposition: Anhang" -Header mit der Datei zurück, wodurch der Browser den "Speichern" -Dialog anzeigt. Der Browser löst jedoch kein "load" -Ereignis im iframe aus.

Ein Ansatz, den ich ausprobiert habe, ist die Verwendung einer mehrteiligen Antwort. Es wird also eine leere HTML-Datei sowie die angehängte herunterladbare Datei gesendet. Zum Beispiel:

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

Dies funktioniert in Firefox. Es empfängt die leere HTML-Datei, löst das Ereignis "load" aus und zeigt dann das Dialogfeld "Save" für die herunterladbare Datei an. Aber es schlägt fehl auf IE und Safari; IE löst das "load" -Ereignis aus, lädt aber die Datei nicht herunter, und Safari lädt die Datei herunter (mit dem falschen Wert) name und content-type) und löst das "load" -Ereignis nicht aus.

Ein anderer Ansatz könnte darin bestehen, einen Anruf zu tätigen, um die Dateierstellung zu starten, dann den Server abzufragen, bis er bereit ist, und dann die bereits erstellte Datei herunterzuladen. Es ist mir jedoch lieber, keine temporären Dateien auf dem Server zu erstellen.

Hat jemand eine bessere Idee?

452
JW.

Ein mögliche Lösung verwendet JavaScript auf dem Client.

Der Client-Algorithmus:

  1. Generieren Sie ein zufälliges eindeutiges Token.
  2. Senden Sie die Download-Anfrage und fügen Sie das Token in ein GET/POST-Feld ein.
  3. Anzeige "Warten" anzeigen.
  4. Starten Sie einen Timer und suchen Sie jede Sekunde nach einem Cookie mit dem Namen "fileDownloadToken" (oder was auch immer Sie entscheiden).
  5. Wenn das Cookie vorhanden ist und sein Wert mit dem Token übereinstimmt, blenden Sie die Anzeige "Warten" aus.

Der Server-Algorithmus:

  1. Suchen Sie in der Anfrage nach dem Feld GET/POST.
  2. Wenn der Wert nicht leer ist, löschen Sie ein Cookie (z. B. "fileDownloadToken") und setzen Sie den Wert auf den Wert des Tokens.

Client-Quellcode (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;
}

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

Wo:

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

Eine sehr einfache (und lahme) einzeilige Lösung besteht darin, das Ereignis window.onblur() zu verwenden, um den Ladedialog zu schließen. Wenn es zu lange dauert und der Benutzer sich entscheidet, etwas anderes zu tun (z. B. E-Mails zu lesen), wird der Ladedialog geschlossen.

27
birdman

alter Thread, ich weiß ...

aber diejenigen, die hier von google geführt werden, interessieren sich vielleicht für meine lösung. es ist sehr einfach und dennoch zuverlässig. und es macht es möglich, echte Fortschrittsmeldungen anzuzeigen (und kann leicht in bestehende Prozesse eingebunden werden):

das Skript, das verarbeitet (mein Problem war: Abrufen von Dateien über http und Liefern als Zip), schreibt den Status in die Sitzung.

der Status wird jede Sekunde abgefragt und angezeigt. das ist alles (ok, es ist nicht so. man muss sich um viele Details kümmern [zB gleichzeitige Downloads], aber es ist ein guter Ort, um anzufangen ;-)).

die Downloadseite:

    <a href="download.php?id=1" class="download">DOWNLOAD 1</a>
    <a href="download.php?id=2" class="download">DOWNLOAD 2</a>
    ...
    <div id="wait">
    Please wait...
    <div id="statusmessage"></div>
    </div>
    <script>
//this is jquery
    $('a.download').each(function()
       {
        $(this).click(
             function(){
               $('#statusmessage').html('prepare loading...');
               $('#wait').show();
               setTimeout('getstatus()', 1000);
             }
          );
        });
    });
    function getstatus(){
      $.ajax({
          url: "/getstatus.php",
          type: "POST",
          dataType: 'json',
          success: function(data) {
            $('#statusmessage').html(data.message);
            if(data.status=="pending")
              setTimeout('getstatus()', 1000);
            else
              $('#wait').hide();
          }
      });
    }
    </script>

getstatus.php

<?php
session_start();
echo json_encode($_SESSION['downloadstatus']);
?>

download.php

    <?php
    session_start();
    $processing=true;
    while($processing){
      $_SESSION['downloadstatus']=array("status"=>"pending","message"=>"Processing".$someinfo);
      session_write_close();
      $processing=do_what_has_2Bdone();
      session_start();
    }
      $_SESSION['downloadstatus']=array("status"=>"finished","message"=>"Done");
//and spit the generated file to the browser
    ?>
12
bytepirate

ich benutze das Folgende, um Blobs herunterzuladen und die Objekt-URL nach dem Download zu widerrufen. es funktioniert in chrome und 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;
}

nachdem der Dateidownload-Dialog geschlossen wurde, erhält das Fenster den Fokus zurück, sodass das Fokusereignis ausgelöst wird.

10
Elmer

Ich habe eine einfache JavaScript-Klasse geschrieben, die eine Technik ähnlich der in bulltorious answer beschriebenen implementiert. Ich hoffe, es kann jemandem hier nützlich sein. Das GitHub-Projekt heißt response-monitor.js

Standardmäßig wird spin.js als Warteanzeige verwendet, es werden jedoch auch eine Reihe von Rückrufen für die Implementierung einer benutzerdefinierten Anzeige bereitgestellt.

JQuery wird unterstützt, ist jedoch nicht erforderlich.

Bemerkenswerte Funktionen

  • Einfache Integration
  • Keine Abhängigkeiten
  • JQuery-Plug-In (optional)
  • Spin.js-Integration (optional)
  • Konfigurierbare Rückrufe zur Überwachung von Ereignissen
  • Verarbeitet mehrere gleichzeitige Anforderungen
  • Serverseitige Fehlererkennung
  • Timeout-Erkennung
  • Cross-Browser

Beispielverwendung

HTML

<!-- the response monitor implementation -->
<script src="response-monitor.js"></script>

<!-- optional JQuery plug-in -->
<script src="response-monitor.jquery.js"></script> 

<a class="my_anchors" href="/report?criteria1=a&criteria2=b#30">Link 1 (Timeout: 30s)</a>
<a class="my_anchors" href="/report?criteria1=b&criteria2=d#10">Link 2 (Timeout: 10s)</a>

<form id="my_form" method="POST">
    <input type="text" name="criteria1">
    <input type="text" name="criteria2">
    <input type="submit" value="Download Report">
</form>

Client (einfaches JavaScript)

//registering multiple anchors at once
var my_anchors = document.getElementsByClassName('my_anchors');
ResponseMonitor.register(my_anchors); //clicking on the links initiates monitoring

//registering a single form
var my_form = document.getElementById('my_form');
ResponseMonitor.register(my_form); //the submit event will be intercepted and monitored

Client (JQuery)

$('.my_anchors').ResponseMonitor();
$('#my_form').ResponseMonitor({timeout: 20});

Client mit Rückrufen (JQuery)

//when options are defined, the default spin.js integration is bypassed
var options = {
    onRequest: function(token){
        $('#cookie').html(token);
        $('#outcome').html('');
        $('#duration').html(''); 
    },
    onMonitor: function(countdown){
        $('#duration').html(countdown); 
    },
    onResponse: function(status){
        $('#outcome').html(status==1?'success':'failure');
    },
    onTimeout: function(){
        $('#outcome').html('timeout');
    }
};

//monitor all anchors in the document
$('a').ResponseMonitor(options);

Server (PHP)

$cookiePrefix = 'response-monitor'; //must match the one set on the client options
$tokenValue = $_GET[$cookiePrefix];
$cookieName = $cookiePrefix.'_'.$tokenValue; //ex: response-monitor_1419642741528

//this value is passed to the client through the ResponseMonitor.onResponse callback
$cookieValue = 1; //for ex, "1" can interpret as success and "0" as failure

setcookie(
    $cookieName,
    $cookieValue,
    time()+300,            // expire in 5 minutes
    "/",
    $_SERVER["HTTP_Host"],
    true,
    false
);

header('Content-Type: text/plain');
header("Content-Disposition: attachment; filename=\"Response.txt\"");

sleep(5); //simulate whatever delays the response
print_r($_REQUEST); //dump the request in the text file

Weitere Beispiele finden Sie im Ordner examples im Repository.

8
Jorge Paulo

Wenn Sie eine Datei streamen, die Sie dynamisch generieren, und außerdem eine Echtzeit-Server-zu-Client-Messaging-Bibliothek implementiert haben, können Sie Ihren Client ganz einfach benachrichtigen.

Die Server-zu-Client-Messaging-Bibliothek, die mir gefällt und die ich empfehle, ist Socket.io (über Node.js). Nachdem Ihr Serverskript die Datei generiert hat, die zum Herunterladen gestreamt wird, kann Ihre letzte Zeile in diesem Skript eine Nachricht an Socket.io senden, die eine Benachrichtigung an den Client sendet. Auf dem Client wartet Socket.io auf eingehende Nachrichten, die vom Server gesendet werden, und ermöglicht es Ihnen, auf diese zu reagieren. Der Vorteil dieser Methode gegenüber anderen ist, dass Sie ein "echtes" Abschlussereignis erkennen können, nachdem das Streaming abgeschlossen ist.

Sie können beispielsweise Ihre Besetztanzeige anzeigen, nachdem auf einen Download-Link geklickt wurde, Ihre Datei streamen, eine Nachricht vom Server in der letzten Zeile Ihres Streaming-Skripts an Socket.io senden, den Client auf eine Benachrichtigung überwachen und die Benachrichtigung erhalten und aktualisieren Sie Ihre Benutzeroberfläche, indem Sie die Besetztanzeige ausblenden.

Ich weiß, dass die meisten Leute, die Antworten auf diese Frage lesen, möglicherweise nicht über diese Art von Einrichtung verfügen, aber ich habe diese exakte Lösung in meinen eigenen Projekten mit großer Wirkung eingesetzt und sie funktioniert wunderbar.

Socket.io ist unglaublich einfach zu installieren und zu verwenden. Weitere Informationen: http://socket.io/

5
Art Geigel

Anhand von Elmers Beispiel habe ich meine eigene Lösung vorbereitet. Nachdem Elemente mit einer definierten Download-Klasse angeklickt wurden, können benutzerdefinierte Meldungen auf dem Bildschirm angezeigt werden. Ich habe einen Fokus Auslöser verwendet, um die Nachricht auszublenden.

JavaScript

$(function(){$('.download').click(function() { ShowDownloadMessage(); }); })

function ShowDownloadMessage()
{
     $('#message-text').text('your report is creating, please wait...');
     $('#message').show();
     window.addEventListener('focus', HideDownloadMessage, false);
}

function HideDownloadMessage(){
    window.removeEventListener('focus', HideDownloadMessage, false);                   
    $('#message').hide();
}

HTML

<div id="message" style="display: none">
    <div id="message-screen-mask" class="ui-widget-overlay ui-front"></div>
    <div id="message-text" class="ui-dialog ui-widget ui-widget-content ui-corner-all ui-front ui-draggable ui-resizable waitmessage">please wait...</div>
</div>

Jetzt sollten Sie jedes Element zum Herunterladen implementieren:

<a class="download" href="file://www.ocelot.com.pl/prepare-report">Download report</a>

oder

<input class="download" type="submit" value="Download" name="actionType">

Nach jedem Download Klick sehen Sie die Meldung Ihr Bericht wird erstellt, bitte warten ...

5
Jerzy Gebler

Ich komme sehr spät zur Party, aber ich werde das hier aufführen, wenn jemand anderes meine Lösung wissen möchte:

Ich hatte wirklich Probleme mit diesem genauen Problem, aber ich fand eine praktikable Lösung mit Iframes (ich weiß, ich weiß. Es ist schrecklich, aber es funktioniert für ein einfaches Problem, das ich hatte).

Ich hatte eine HTML-Seite, die ein separates PHP-Skript startete, das die Datei erzeugte und sie dann herunterlud. Auf der HTML-Seite habe ich die folgende JQuery im HTML-Header verwendet (Sie müssen auch eine JQuery-Bibliothek hinzufügen):

<script>
    $(function(){
        var iframe = $("<iframe>", {name: 'iframe', id: 'iframe',}).appendTo("body").hide();
        $('#click').on('click', function(){
            $('#iframe').attr('src', 'your_download_script.php');
        });
        $('iframe').load(function(){
            $('#iframe').attr('src', 'your_download_script.php?download=yes'); <!--on first iframe load, run script again but download file instead-->
            $('#iframe').unbind(); <!--unbinds the iframe. Helps prevent against infinite recursion if the script returns valid html (such as echoing out exceptions) -->
        });
    });
</script>

In your_download_script.php haben Sie folgende Möglichkeiten:

function downloadFile($file_path) {
    if (file_exists($file_path)) {
        header('Content-Description: File Transfer');
        header('Content-Type: text/csv');
        header('Content-Disposition: attachment; filename=' . basename($file_path));
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');
        header('Content-Length: ' . filesize($file_path));
        ob_clean();
        flush();
        readfile($file_path);
        exit();
    }
}


$_SESSION['your_file'] = path_to_file; //this is just how I chose to store the filepath

if (isset($_REQUEST['download']) && $_REQUEST['download'] == 'yes') {
    downloadFile($_SESSION['your_file']);
} else {
    *execute logic to create the file*
}

Um dies zu beheben, startet jquery zuerst Ihr PHP-Skript in einem Iframe. Der Iframe wird geladen, sobald die Datei generiert wurde. Anschließend startet jquery das Skript erneut mit einer Anforderungsvariablen, die das Skript auffordert, die Datei herunterzuladen.

Der Grund dafür, dass Sie den Download und die Dateierzeugung nicht auf einmal ausführen können, liegt an der Funktion php header (). Wenn Sie header () verwenden, ändern Sie das Skript in etwas anderes als eine Webseite und jquery erkennt das Download-Skript nie als "geladen". Ich weiß, dass dies nicht unbedingt darauf zurückzuführen ist, dass ein Browser eine Datei empfängt, aber Ihr Problem klang ähnlich wie meines.

3
Walker Boh

Wenn der Benutzer die Generierung der Datei auslöst, können Sie diesem "Download" einfach eine eindeutige ID zuweisen und den Benutzer zu einer Seite senden, die alle paar Sekunden aktualisiert (oder mit AJAX überprüft). Sobald die Datei fertig ist, speichern Sie sie unter derselben eindeutigen ID und ...

  • Wenn die Datei fertig ist, führen Sie den Download durch.
  • Wenn die Datei noch nicht fertig ist, zeigen Sie den Fortschritt an.

Dann können Sie das ganze iFrame/Warten/Browserfenster-Chaos überspringen und haben dennoch eine wirklich elegante Lösung.

3
gahooa

Wenn Sie die Datei nicht generieren und auf dem Server speichern möchten, möchten Sie den Status speichern, z. Datei in Bearbeitung, Datei vollständig? Ihre "wartende" Seite könnte den Server abfragen, um zu erfahren, wann die Dateierzeugung abgeschlossen ist. Sie würden nicht sicher wissen, ob der Browser den Download gestartet hat, aber Sie hätten ein gewisses Vertrauen.

3
bmb

Ich hatte genau das gleiche Problem. Meine Lösung bestand darin, temporäre Dateien zu verwenden, da ich bereits eine Reihe temporärer Dateien generiert habe. Das Formular wird eingereicht mit:

var microBox = {
    show : function(content) {
        $(document.body).append('<div id="microBox_overlay"></div><div id="microBox_window"><div id="microBox_frame"><div id="microBox">' +
        content + '</div></div></div>');
        return $('#microBox_overlay');
    },

    close : function() {
        $('#microBox_overlay').remove();
        $('#microBox_window').remove();
    }
};

$.fn.bgForm = function(content, callback) {
    // Create an iframe as target of form submit
    var id = 'bgForm' + (new Date().getTime());
    var $iframe = $('<iframe id="' + id + '" name="' + id + '" style="display: none;" src="about:blank"></iframe>')
        .appendTo(document.body);
    var $form = this;
    // Submittal to an iframe target prevents page refresh
    $form.attr('target', id);
    // The first load event is called when about:blank is loaded
    $iframe.one('load', function() {
        // Attach listener to load events that occur after successful form submittal
        $iframe.load(function() {
            microBox.close();
            if (typeof(callback) == 'function') {
                var iframe = $iframe[0];
                var doc = iframe.contentWindow.document;
                var data = doc.body.innerHTML;
                callback(data);
            }
        });
    });

    this.submit(function() {
        microBox.show(content);
    });

    return this;
};

$('#myForm').bgForm('Please wait...');

Am Ende des Skripts, das die Datei generiert, habe ich:

header('Refresh: 0;url=fetch.php?token=' . $token);
echo '<html></html>';

Dadurch wird das Ladeereignis für den Iframe ausgelöst. Dann wird die Wartemeldung geschlossen und der Dateidownload gestartet. Getestet auf IE7 und Firefox.

2
grom

Wenn Sie eine Datei heruntergeladen haben, die nicht im Dokument, sondern gespeichert wurde, können Sie nicht feststellen, wann der Download abgeschlossen ist, da dies nicht im Bereich des aktuellen Dokuments liegt, sondern in einem separaten Prozess im Browser.

"Wie erkenne ich, wann der Browser den Download von Dateien erhält?"
Ich hatte das gleiche Problem mit dieser Konfiguration:
Streben 1.2.9
jquery-1.3.2.
jquery-ui-1.7.1.custom
IE 11
Java 5


Meine Lösung mit einem Cookie:
- Clientseite:
Rufen Sie beim Absenden Ihres Formulars Ihre Javascript-Funktion auf, um Ihre Seite auszublenden und Ihren wartenden Spinner zu laden

function loadWaitingSpinner(){
... hide your page and show your spinner ...
}

Rufen Sie dann eine Funktion auf, die alle 500 ms überprüft, ob ein Cookie vom Server kommt.

function checkCookie(){
    var verif = setInterval(isWaitingCookie,500,verif);
}

Wenn das Cookie gefunden wird, beenden Sie die Überprüfung alle 500 ms, setzen Sie das Cookie außer Kraft und rufen Sie Ihre Funktion auf, um zu Ihrer Seite zurückzukehren und den wartenden Spinner zu entfernen ( removeWaitingSpinner () ). Es ist wichtig, dass der Cookie verfällt, wenn Sie eine andere Datei erneut herunterladen möchten!

function isWaitingCookie(verif){
    var loadState = getCookie("waitingCookie");
    if (loadState == "done"){
        clearInterval(verif);
        document.cookie = "attenteCookie=done; expires=Tue, 31 Dec 1985 21:00:00 UTC;";
        removeWaitingSpinner();
    }
}
    function getCookie(cookieName){
        var name = cookieName + "=";
        var cookies = document.cookie
        var cs = cookies.split(';');
        for (var i = 0; i < cs.length; i++){
            var c = cs[i];
            while(c.charAt(0) == ' ') {
                c = c.substring(1);
            }
            if (c.indexOf(name) == 0){
                return c.substring(name.length, c.length);
            }
        }
        return "";
    }
function removeWaitingSpinner(){
... come back to your page and remove your spinner ...
}

- Serverseite:
Fügen Sie am Ende Ihres Serverprozesses der Antwort ein Cookie hinzu. Dieses Cookie wird an den Client gesendet, sobald Ihre Datei zum Download bereitsteht.

Cookie waitCookie = new Cookie("waitingCookie", "done");
response.addCookie(waitCookie);

Ich hoffe, jemandem zu helfen!

1
MB33

Eine schnelle Lösung, wenn Sie nur eine Nachricht oder ein Ladeprogramm-GIF anzeigen möchten, bis der Download-Dialog angezeigt wird, besteht darin, die Nachricht in einem versteckten Container abzulegen. Wenn Sie auf die Schaltfläche klicken, die die herunterzuladende Datei generiert, machen Sie den Container sichtbar. Verwenden Sie dann jquery oder javascript, um das focusout-Ereignis der Schaltfläche abzufangen und den Container auszublenden, der die Nachricht enthält

0
Mihaela Rada

Die Frage ist, ob beim Generieren einer Datei eine Warteanzeige angezeigt wird, die sich nach dem Herunterladen der Datei wieder normalisiert. Die Art und Weise, wie ich das mache, ist die Verwendung eines versteckten iFrames und das Verknüpfen des Onload-Ereignisses des Frames, um meine Seite über den Beginn des Downloads zu informieren. , ABER onload wird nicht in IE für Dateidownloads (wie beim Header-Token für Anhänge) ausgelöst. Das Abrufen des Servers funktioniert. Aber ich mag die zusätzliche Komplexität nicht. Also hier ist was ich tue:

  • Zielen Sie wie gewohnt auf den versteckten iFrame.
  • Generieren Sie den Inhalt. Zwischenspeichern mit einem absoluten Timeout in 2 Minuten.
  • Senden Sie eine JavaScript-Umleitung zurück an den aufrufenden Client, und rufen Sie die Generatorseite im Wesentlichen ein zweites Mal auf. HINWEIS: Dadurch wird das Onload-Ereignis in IE) ausgelöst, da es sich wie eine normale Seite verhält.
  • Entfernen Sie den Inhalt aus dem Cache und senden Sie ihn an den Client.

Haftungsausschluss: Tun Sie dies nicht auf einer stark frequentierten Site, da sich das Caching summieren könnte. Aber wirklich, wenn Ihre Sites, die den lang andauernden Prozess beschäftigen, Sie sowieso von Threads verhungern lassen.

So sieht der Codebehind aus, das ist alles, was Sie wirklich brauchen.

public partial class Download : System.Web.UI.Page
{
    protected System.Web.UI.HtmlControls.HtmlControl Body;

    protected void Page_Load( object sender, EventArgs e )
    {
        byte[ ] data;
        string reportKey = Session.SessionID + "_Report";

        // Check is this page request to generate the content
        //    or return the content (data query string defined)
        if ( Request.QueryString[ "data" ] != null )
        {
            // Get the data and remove the cache
            data = Cache[ reportKey ] as byte[ ];
            Cache.Remove( reportKey );

            if ( data == null )                    
                // send the user some information
                Response.Write( "Javascript to tell user there was a problem." );                    
            else
            {
                Response.CacheControl = "no-cache";
                Response.AppendHeader( "Pragma", "no-cache" );
                Response.Buffer = true;

                Response.AppendHeader( "content-disposition", "attachment; filename=Report.pdf" );
                Response.AppendHeader( "content-size", data.Length.ToString( ) );
                Response.BinaryWrite( data );
            }
            Response.End();                
        }
        else
        {
            // Generate the data here. I am loading a file just for an example
            using ( System.IO.FileStream stream = new System.IO.FileStream( @"C:\1.pdf", System.IO.FileMode.Open ) )
                using ( System.IO.BinaryReader reader = new System.IO.BinaryReader( stream ) )
                {
                    data = new byte[ reader.BaseStream.Length ];
                    reader.Read( data, 0, data.Length );
                }

            // Store the content for retrieval              
            Cache.Insert( reportKey, data, null, DateTime.Now.AddMinutes( 5 ), TimeSpan.Zero );

            // This is the key bit that tells the frame to reload this page 
            //   and start downloading the content. NOTE: Url has a query string 
            //   value, so that the content isn't generated again.
            Body.Attributes.Add("onload", "window.location = 'binary.aspx?data=t'");
        }
    }
0
MarcLawrence

Wenn Xmlhttprequest with blob keine Option ist, können Sie Ihre Datei in einem neuen Fenster öffnen und prüfen, ob in diesem Fenster mit Intervall Eny-Elemente eingefügt werden.

var form = document.getElementById("frmDownlaod");
 form.setAttribute("action","downoad/url");
 form.setAttribute("target","downlaod");
 var exportwindow = window.open("", "downlaod", "width=800,height=600,resizable=yes");
 form.submit();

var responseInterval = setInterval(function(){
        var winBody = exportwindow.document.body
        if(winBody.hasChildNodes()) // or 'downoad/url' === exportwindow.document.location.href
        {
                clearInterval(responseInterval);
                // do your work
                // if there is error page configured your application for failed requests, check for those dom elemets 
        }
}, 1000)
//Better if you specify maximun no of intervals
0
aniketKumkar