2009-07-09 2 views
395

У меня есть страница, которая позволяет пользователю загружать динамически сгенерированный файл. Для создания требуется много времени, поэтому я бы хотел показать индикатор ожидания. Проблема в том, что я не могу понять, как определить, когда браузер получил файл, поэтому я могу скрыть индикатор.Обнаруживать, когда браузер получает загрузку файла

Я делаю запрос в скрытой форме, которая отправляется на сервер и нацелена на скрытый iframe для его результатов. Поэтому я не заменяю все окно браузера на результат. Я слушаю событие «load» на iframe, в надежде, что оно будет срабатывать, когда загрузка будет завершена.

Я возвращаю заголовок «Content-Disposition: attachment» с файлом, что заставляет браузер отображать диалог «Сохранить». Но браузер не запускает событие «load» в 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-файл, запускает событие «load», затем показывает диалоговое окно «Сохранить» для загружаемого файла. Но он не работает на IE и Safari; IE запускает событие «load», но не загружает файл, и Safari загружает файл (с неправильным именем и типом содержимого) и не запускает событие «load».

Другой подход может заключаться в том, чтобы позвонить, чтобы начать создание файла, а затем опросить сервер, пока он не будет готов, а затем загрузите уже созданный файл. Но я бы предпочел не создавать временные файлы на сервере.

У кого-нибудь есть идея?

+3

Нет версии IE поддерживает многокомпонентные/х-смешанных заменить. – EricLaw

+0

Спасибо Эрик - это хорошо знать. Я больше не буду тратить время на этот подход. –

+0

Только надежный способ, похоже, является уведомлением о push-сервере (SignalR для людей ASP.NET). – dudeNumber4

ответ

371

Один possible solution использует JavaScript на клиенте.

Алгоритм клиента:

  1. Генерация случайных уникальный маркер.
  2. Отправьте запрос на загрузку и включите токен в поле GET/POST.
  3. Показать индикатор ожидания.
  4. Запустите таймер, и каждую секунду или около того найдите файл cookie с именем «fileDownloadToken» (или все, что вы решите).
  5. Если файл cookie существует, и его значение соответствует токену, скройте индикатор ожидания.

Алгоритм сервера:

  1. Посмотрите на поле GET/POST в запросе.
  2. Если у него есть непустое значение, отбросьте файл 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 
    ); 
} 
+4

Удивительная идея, я использовал ее как базовую структуру [для этого ответа] (http://stackoverflow.com/a/9049986/585552) a bout загрузка нескольких файлов с помощью jQuery/C# – Greg

+1

увы, невозможно с файлами на s3, так как вы не можете установить файлы cookie. – jedierikb

+5

Головы для других: если document.cookies не включает downloadToken, проверьте путь к файлу cookie. В моем случае мне пришлось установить путь к «/» на стороне сервера (например, cookie.setPath («/») в Java), хотя по умолчанию путь был пустым. Некоторое время я думал, что проблема связана с обработкой файлов cookie домена «localhost» (http://stackoverflow.com/questions/1134290/cookies-on-localhost-with-explicit-domain), но это не было проблемой в конец. Может быть, для других, хотя так стоит прочитать. – jlpp

-1

Если вы загрузили файл, который был сохранен, в отличие от того, чтобы быть в документе, невозможно определить, когда загрузка будет завершена, так как она не входит в объем текущего документа, а отдельный процесс в браузере.

+8

Я должен уточнить - я не слишком озабочен тем, когда загрузка * завершается *. Если я могу просто определить, когда начнется загрузка, этого будет достаточно. –

3

Когда пользователь запускает генерацию файла, вы можете просто назначить уникальный идентификатор этой «загрузке» и отправить пользователя на страницу, которая обновляет (или проверяет с помощью AJAX) каждые несколько секунд. Как только файл будет завершен, сохраните его под тем же уникальным идентификатором и ...

  • Если файл готов, выполните загрузку.
  • Если файл не готов, покажите ход выполнения.

Тогда вы можете пропустить весь беспорядок iframe/waiting/browserwindow, но у вас действительно элегантное решение.

+0

Это звучит как подход временного файла, о котором я упоминал выше Я могу сделать что-то вроде этого, если окажется, что моя идея невозможна, но я надеялся ее избежать. –

2

Если вы не хотите создавать и хранить файл на сервере, согласны ли вы сохранить его статус, например. файл в процессе, полный файл? Ваша страница ожидания может опросить сервер, чтобы узнать, когда будет завершено создание файла. Вы не знали бы наверняка, что браузер начал загрузку, но у вас будет определенная уверенность.

2

У меня была такая же проблема. Мое решение заключалось в использовании временных файлов, так как я уже создавал кучу временных файлов.Форма представляется с:

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...'); 

В конце сценария, который создает файл у меня есть:

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

Это вызовет событие нагрузки на IFRAME уволят. Затем сообщение ожидания будет закрыто, и загрузка файла начнется. Протестировано на IE7 и Firefox.

0

Вопрос заключается в наличии индикатора «ожидания» во время создания файла и последующего возврата к нормальному состоянию после загрузки файла. Как мне нравится делать это, используйте скрытый iFrame и подключайте событие onload к фрейму, чтобы моя страница знала, когда начнется загрузка. BUT onload не запускается в IE для загрузки файлов (например, с токеном заголовка вложения). Опрос сервера работает, но мне не нравится дополнительная сложность. Итак, вот что я делаю:

  • Задайте скрытый iFrame, как обычно.
  • Сформировать содержание. Кэшировать с абсолютный тайм-аут через 2 минуты.
  • Отправить javascript redirect обратно в вызывающий клиент, по существу вызывающий страницу генератора во второй раз. ПРИМЕЧАНИЕ. Это приведет к тому, что событие onload будет запущено в IE, потому что оно действует как обычная страница.
  • Удалить содержимое из кеша, а отправить его клиенту.

Отказ от ответственности, не делайте этого на занятой площадке из-за того, что кеширование может складываться. Но на самом деле, если ваши сайты, занятые длительным запуском процесса, будут голодать в любом случае.

Вот что выглядит codebehind, и это все, что вам действительно нужно.

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'"); 
     } 
    } 
11

старой нить, я знаю ...

, но те, которые ведут здесь Google может быть заинтересована в моем решении. Очень прост, но надежно. и он позволяет отображать реальные сообщения о проделанной работе (и их можно легко подключить к существующим процессам):

сценарий, который обрабатывает (моя проблема: получение файлов через http и доставка их как zip) записывает статус в сессия.

статус проверяется и отображается каждую секунду. thats all (ok, его нет, вам нужно позаботиться о большом количестве деталей (например, одновременные загрузки), но это хорошее место для начала ;-)).

downloadpage:

<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 
    ?> 
+3

, но если у пользователя открыто несколько окон или загрузок, вы также получаете избыточный вызов на сервер – Yuki

+0

Если у вас есть несколько подключений от одного пользователя, все они будут ждать завершения других соединений, потому что session_start() блокирует сеанс для пользователя и запрещает всем другим процессам доступ к нему. –

+1

вам не нужно использовать '.each()' для регистрации событий. просто скажите '$ ('a.download'). click()' – robisrob

26

очень просто (и хромой) одна строка так Чтобы закрыть диалоговое окно загрузки, необходимо использовать событие window.onblur(). Конечно, если это занимает слишком много времени, и пользователь решает сделать что-то еще (например, читать электронные письма), диалог загрузки будет закрыт.

+0

Это простой подход, который идеально подходит для избавления от загружаемого наложения для загрузки файла, который был запущен с помощью 'onbeforeunload' Спасибо. – wf4

+4

Это не работает во всех браузерах (некоторые не оставляют/размывают текущее окно как часть рабочего процесса загрузки, например Safari, некоторые версии IE и т. Д.). – hiattp

+0

Chrome и другие подобные браузеры автоматически загружают файлы, в которых это условие терпит неудачу. – Lucky

11

Я использую следующие, чтобы загрузить blobs и аннулировать объект-url после загрузки. он работает в chrome и 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; 
} 

после того, как диалоговое окно загрузки файла закрыто, окно возвращает ее фокус назад, так что происходит событие фокусировки.

+0

. Еще есть проблема переключения окна и возврата, который будет заставить модальное скрыть. – dudeNumber4

+3

Браузеры, такие как Chrome, которые загружаются в нижний лоток, никогда не размывают/переориентируют окно. – Coleman

-2

Создайте iframe при нажатии кнопки/ссылки и добавьте его в тело.

    $('<iframe />') 
       .attr('src', url) 
       .attr('id','iframe_download_report') 
       .hide() 
       .appendTo('body'); 

Создайте iframe с задержкой и удалите его после загрузки.

      var triggerDelay = 100; 
          var cleaningDelay = 20000; 
          var that = this; 
          setTimeout(function() { 
           var frame = $('<iframe style="width:1px; height:1px;" class="multi-download-frame"></iframe>'); 
           frame.attr('src', url+"?"+ "Content-Disposition: attachment ; filename="+that.model.get('fileName')); 
           $(ev.target).after(frame); 
           setTimeout(function() { 
            frame.remove(); 
           }, cleaningDelay); 
          }, triggerDelay); 
+0

Отсутствует информация, и она не решает проблему «когда скрывать загрузку». –

3

Основываясь на примере Эльмера, я подготовил собственное решение. После элементов нажмите с определенными скачать класс позволяет отображать пользовательские сообщения на экране. Я использовал фокус триггер, чтобы скрыть сообщение.

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> 

Теперь вы должны реализовать любой элемент для загрузки:

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

или

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

После каждого загрузки щелчком мыши вы увидите сообщение отчет создает, пожалуйста, подождите ...

+0

Что делать, если пользователь нажимает на окно? –

3

Я очень поздно к партии, но я положу это здесь, если кто-нибудь else хотел бы знать мое решение:

У меня была настоящая борьба с этой точной проблемой, но я нашел жизнеспособное решение с использованием iframes (знаю, я знаю. Это ужасно, но это работает для простой проблемы, что у меня было)

У меня была html-страница, которая запустила отдельный скрипт php, который сгенерировал файл, а затем загрузил его. На странице HTML, я использовал следующий JQuery в заголовке HTML (вам необходимо включить библиотеку Jquery, а):

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

На your_download_script.php, имеют следующие:

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

Чтобы прервать это, jquery сначала запускает ваш php-скрипт в iframe. Iframe загружается после создания файла. Затем jquery снова запускает скрипт с переменной запроса, сообщающей сценарию для загрузки файла.

Причина, по которой вы не можете выполнить загрузку и создание файлов за один раз из-за функции php header(). Если вы используете header(), вы меняете скрипт на что-то другое, кроме веб-страницы, и jquery никогда не распознает сценарий загрузки как «загруженный». Я знаю, что это может не обязательно обнаруживать, когда браузер получает файл, но ваша проблема была похожа на мою.

5

Я написал простой класс JavaScript, который реализует технику, аналогичную той, которая описана в актуальном answer. Надеюсь, это может быть полезно кому-то здесь. Проект GitHub называется response-monitor.js

По умолчанию используется spin.js как индикатор ожидания, но он также предоставляет набор функций обратного вызова для реализации пользовательского индикатора.

JQuery поддерживается, но не требуется.

Особенности

  • Простая интеграция
  • Нет зависимостей
  • JQuery плагина (по желанию)
  • отжима.JS интеграции (необязательно)
  • Конфигурируемые обратные вызовы для событий мониторинга
  • Обработка нескольких одновременных запросов
  • обнаружения ошибок на стороне сервера
  • обнаружения таймаута
  • Кросс-браузер

Пример использования

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 (обычный 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 с обратными вызовами (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); 

сервера (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 

Для получения дополнительных примеров проверьте папку examples в репозитории.

2

Если вы загружаете файл, который генерируете динамически, а также имеете встроенную библиотеку обмена сообщениями от сервера к клиенту, вы можете легко оповестить своего клиента.

Библиотека обмена сообщениями между клиентом, которую мне нравится и порекомендована, - Socket.io (через Node.js). После того, как ваш серверный сценарий будет создан, генерирующий файл, который будет передан для загрузки, ваша последняя строка в этом скрипте может передать сообщение Socket.io, которое отправляет уведомление клиенту. На клиенте Socket.io прослушивает входящие сообщения, исходящие от сервера, и позволяет вам действовать на них. Преимущество использования этого метода над другими заключается в том, что вы можете обнаружить «истинное» событие завершения после потоковой передачи.

Например, вы можете отображать индикатор занятости после того, как щелкнули ссылку загрузки, передайте файл, выпустите сообщение на Socket.io с сервера в последней строке вашего потокового скрипта, выслушайте клиента для уведомления , получать уведомление и обновлять свой пользовательский интерфейс, скрывая индикатор занятости.

Я понимаю, что большинство людей, читающих ответы на этот вопрос, возможно, не имеют такого типа установки, но я использовал это точное решение для большого эффекта в моих собственных проектах, и оно работает чудесно.

Socket.io невероятно прост в установке и использовании. См. Больше: http://socket.io/

0

Быстрое решение, если вы хотите отображать сообщение или gif загрузчика до тех пор, пока не появится диалоговое окно загрузки, - это отправить сообщение в скрытый контейнер и щелкнуть по кнопке, которая сгенерирует файл скачайте, вы делаете контейнер видимым. Затем используйте jquery или javascript, чтобы поймать событие фокуса кнопки, чтобы скрыть контейнер, содержащий сообщение

0

Если Xmlhttprequest с blob не является вариантом, вы можете открыть файл в новом окне и проверить, заполняются ли элементы eny в это корпус окна с интервалом.

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(){ 
 
\t var winBody = exportwindow.document.body 
 
\t if(winBody.hasChildNodes()) // or 'downoad/url' === exportwindow.document.location.href 
 
\t { 
 
\t \t clearInterval(responseInterval); 
 
\t \t // do your work 
 
\t \t // if there is error page configured your application for failed requests, check for those dom elemets 
 
\t } 
 
}, 1000) 
 
//Better if you specify maximun no of intervals

Смежные вопросы