Eu tenho uma página que permite ao usuário baixar um arquivo gerado dinamicamente. Demora muito tempo para gerar, então eu gostaria de mostrar um indicador de "espera". O problema é que não consigo descobrir como detectar quando o navegador recebeu o arquivo, para que eu possa ocultar o indicador.
Estou fazendo a solicitação em um formulário oculto, que POSTs para o servidor, e direciona um iframe oculto para seus resultados. Isso é para não substituir a janela inteira do navegador pelo resultado. Eu escuto um evento "load" no iframe, na esperança de que ele seja acionado quando o download for concluído.
Retorno um cabeçalho "Disposição de conteúdo: anexo" com o arquivo, o que faz com que o navegador mostre a caixa de diálogo "Salvar". Mas o navegador não dispara um evento "load" no iframe.
Uma abordagem que tentei é usar uma resposta de várias partes. Portanto, ele enviaria um arquivo HTML vazio, bem como o arquivo para download anexado. Por exemplo:
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
Isso funciona no Firefox; ele recebe o arquivo HTML vazio, aciona o evento "load" e mostra a caixa de diálogo "Save" do arquivo para download. Mas falha no IE e no Safari; O IE aciona o evento "load", mas não baixa o arquivo, e o Safari baixa o arquivo (com o nome e o tipo de conteúdo incorretos) e não aciona o evento "load".
Uma abordagem diferente pode ser fazer uma chamada para iniciar a criação do arquivo, pesquisar o servidor até que esteja pronto e fazer o download do arquivo já criado. Mas prefiro evitar criar arquivos temporários no servidor.
Alguém tem uma idéia melhor?
fonte
Respostas:
Uma solução possível usa JavaScript no cliente.
O algoritmo do cliente:
O algoritmo do servidor:
Código fonte do cliente (JavaScript):
Exemplo de código do servidor (PHP):
Onde:
fonte
Uma solução muito simples (e esfarrapada) de uma linha é usar o
window.onblur()
evento para fechar a caixa de diálogo de carregamento. Obviamente, se levar muito tempo e o usuário decidir fazer outra coisa (como ler e-mails), a caixa de diálogo de carregamento será fechada.fonte
onbeforeunload
Obrigado.fio velho, eu sei ...
mas aqueles que são liderados aqui pelo Google podem estar interessados em minha solução. é muito simples, mas confiável. e torna possível exibir mensagens reais de progresso (e pode ser facilmente conectado a processos existentes):
o script que processa (meu problema era: recuperar arquivos via http e entregá-los como zip) grava o status na sessão.
o status é pesquisado e exibido a cada segundo. isso é tudo (ok, não é. você precisa cuidar de muitos detalhes [por exemplo, downloads simultâneos], mas é um bom lugar para começar ;-)).
a página de download:
getstatus.php
download.php
fonte
.each()
para registros de eventos. apenas diga$('a.download').click()
setTimeout('getstatus()', 1000);
. Use o fn diretamente:setTimeout(getstatus, 1000);
Eu uso o seguinte para baixar blobs e revogar o objeto-url após o download. funciona em chrome e firefox!
depois que a caixa de diálogo de download do arquivo é fechada, a janela recupera o foco para que o evento de foco seja acionado.
fonte
Com base no exemplo de Elmer, preparei minha própria solução. Depois que os elementos clicam com a classe de download definida, ele mostra uma mensagem personalizada na tela. Eu usei o foco gatilho de para ocultar a mensagem.
Javascript
HTML
Agora você deve implementar qualquer elemento para fazer o download:
ou
Após cada clique de download, você verá a mensagem que seu relatório está criando, aguarde ...
fonte
Eu escrevi uma classe simples de JavaScript que implementa uma técnica semelhante à descrita em resposta torturante . Espero que possa ser útil para alguém aqui. O projeto GitHub é chamado response-monitor.js
Por padrão, ele usa spin.js como o indicador de espera, mas também fornece um conjunto de retornos de chamada para a implementação de um indicador personalizado.
JQuery é suportado, mas não obrigatório.
Recursos notáveis
Exemplo de uso
HTML
Cliente (JavaScript simples)
Cliente (JQuery)
Cliente com retornos de chamada (JQuery)
Servidor (PHP)
Para mais exemplos, verifique a pasta de exemplos no repositório.
fonte
Estou muito atrasado para a festa, mas vou colocar aqui se alguém quiser saber minha solução:
Eu tive uma luta real com esse problema exato, mas encontrei uma solução viável usando iframes (eu sei, eu sei. É terrível, mas funciona para um problema simples que eu tinha)
Eu tinha uma página html que lançava um script php separado que gerava o arquivo e o baixava. Na página html, usei o seguinte jquery no cabeçalho html (você também precisará incluir uma biblioteca jquery):
Em your_download_script.php, tenha o seguinte:
Para quebrar isso, o jquery primeiro lança seu script php em um iframe. O iframe é carregado assim que o arquivo é gerado. Em seguida, o jquery inicia o script novamente com uma variável de solicitação informando ao script para baixar o arquivo.
O motivo pelo qual você não pode fazer o download e a geração de arquivos de uma só vez é devido à função header () do php. Se você usa o header (), está alterando o script para algo diferente de uma página da Web e o jquery nunca reconhecerá o script de download como 'carregado'. Sei que isso pode não estar necessariamente detectando quando um navegador recebe um arquivo, mas o problema foi semelhante ao meu.
fonte
Se você estiver transmitindo um arquivo que está gerando dinamicamente e também tiver uma biblioteca de mensagens de servidor para cliente em tempo real implementada, poderá alertar seu cliente com bastante facilidade.
A biblioteca de mensagens de servidor para cliente que eu gosto e recomendo é Socket.io (via Node.js.). Após a conclusão do script do servidor, a geração do arquivo que está sendo transmitido para download e sua última linha nesse script pode emitir uma mensagem para o Socket.io, que envia uma notificação ao cliente. No cliente, o Socket.io escuta as mensagens recebidas emitidas pelo servidor e permite que você as atue. O benefício de usar esse método sobre outros é que você é capaz de detectar um evento de conclusão "verdadeiro" após a conclusão da transmissão.
Por exemplo, você pode mostrar seu indicador de ocupado depois de clicar em um link de download, transmitir o arquivo, emitir uma mensagem para o Socket.io do servidor na última linha do seu script de streaming, ouvir uma notificação no cliente, receber a notificação e atualize sua interface do usuário ocultando o indicador de ocupado.
Sei que a maioria das pessoas que lê as respostas para essa pergunta pode não ter esse tipo de configuração, mas usei essa solução exata com grande efeito em meus próprios projetos e funciona maravilhosamente.
O Socket.io é incrivelmente fácil de instalar e usar. Veja mais: http://socket.io/
fonte
"Como detectar quando o navegador recebe o download de arquivos?"
Eu enfrentei o mesmo problema com essa configuração:
struts 1.2.9
jquery-1.3.2.
jquery-ui-1.7.1.custom
IE 11
java 5
Minha solução com um cookie:
- Lado do cliente:
ao enviar seu formulário, chame sua função javascript para ocultar sua página e carregar seu botão giratório em espera
Em seguida, chame uma função que verificará a cada 500ms se um cookie é proveniente do servidor.
Se o cookie for encontrado, pare de verificar a cada 500 ms, expire o cookie e chame sua função para voltar à sua página e remover o botão giratório em espera ( removeWaitingSpinner () ). É importante expirar o cookie se você deseja poder baixar outro arquivo novamente!
- Lado do servidor:
no final do processo do servidor, adicione um cookie à resposta. Esse cookie será enviado ao cliente quando seu arquivo estiver pronto para download.
Espero ajudar alguém!
fonte
Quando o usuário aciona a geração do arquivo, você pode simplesmente atribuir um ID exclusivo a esse "download" e enviar o usuário para uma página que atualiza (ou verifica com o AJAX) a cada poucos segundos. Quando o arquivo terminar, salve-o com o mesmo ID exclusivo e ...
Em seguida, você pode pular toda a confusão de iframe / espera / janela do navegador e ainda ter uma solução realmente elegante.
fonte
Se você não deseja gerar e armazenar o arquivo no servidor, deseja armazenar o status, por exemplo, arquivo em andamento ou arquivo completo? Sua página "em espera" pode consultar o servidor para saber quando a geração do arquivo está concluída. Você não saberia ao certo que o navegador iniciou o download, mas você teria alguma confiança.
fonte
Eu apenas tive exatamente esse mesmo problema. Minha solução foi usar arquivos temporários, já que eu já estava gerando vários arquivos temporários. O formulário é enviado com:
No final do script que gera o arquivo, eu tenho:
Isso fará com que o evento de carregamento no iframe seja acionado. A mensagem de espera é fechada e o download do arquivo será iniciado. Testado no IE7 e Firefox.
fonte
Na minha experiência, existem duas maneiras de lidar com isso:
fonte
Saudações, sei que o tópico é antigo, mas deixo uma solução que vi em outro lugar e funcionou:
Você pode usar isso:
fonte
Se você fez o download de um arquivo salvo, em vez de constar no documento, não há como determinar quando o download é concluído, pois não está no escopo do documento atual, mas em um processo separado no navegador.
fonte
A questão é ter um indicador de 'espera' enquanto um arquivo é gerado e retornar ao normal assim que o arquivo estiver sendo baixado. O jeito que eu gosto disso é usar um iFrame oculto e conectar o evento onload do quadro para informar minha página quando o download for iniciado. MAS onload não é acionado no IE para downloads de arquivos (como no token do cabeçalho do anexo). A pesquisa do servidor funciona, mas não gosto da complexidade extra. Então aqui está o que eu faço:
Isenção de responsabilidade, não faça isso em um site ocupado, pois o armazenamento em cache pode aumentar. Mas, na verdade, se seus sites que ocupam o longo processo de privá-lo de threads de qualquer maneira.
Aqui está a aparência do código, que é tudo o que você realmente precisa.
fonte
Uma solução rápida, se você deseja exibir apenas uma mensagem ou um gif do carregador até a caixa de diálogo de download ser exibida, é colocar a mensagem em um contêiner oculto e, quando você clica no botão que gera o arquivo a ser baixado, torna o contêiner visível. Em seguida, use jquery ou javascript para capturar o evento de foco do botão e ocultar o contêiner que contém a mensagem
fonte
Se Xmlhttprequest com blob não for uma opção, você poderá abrir seu arquivo em uma nova janela e verificar se os elementos eny são preenchidos nesse corpo da janela com intervalo.
fonte
Este exemplo Java / Spring detecta o final de um Download, quando oculta o indicador "Carregando ...".
Abordagem: no lado JS, defina um cookie com uma idade máxima de expiração de 2 min e pesquise a cada segundo a expiração do cookie . Em seguida, o lado do servidor substitui esse cookie por um anterior idade de vencimento - a conclusão do processo do servidor. Assim que a expiração do cookie é detectada na pesquisa JS, "Carregando ..." fica oculto.
JS Side
Servidor Java / Spring
fonte
myCookie.setPath("/"); response.addCookie(myCookie);
O Primefaces também usa pesquisa de cookie
https://github.com/primefaces/primefaces/blob/32bb00299d00e50b2cba430638468a4145f4edb0/src/main/resources/META-INF/resources/primefaces/core/core.js#L458
fonte
Crie um iframe quando o botão / link for clicado e anexe-o ao corpo.
Crie um iframe com atraso e exclua-o após o download.
fonte