Eu tenho um aplicativo javascript que envia solicitações de ajax POST para um determinado URL. A resposta pode ser uma sequência JSON ou um arquivo (como anexo). Posso detectar com facilidade o Tipo de Conteúdo e a Disposição de Conteúdo na minha chamada ajax, mas depois que detecto que a resposta contém um arquivo, como ofereço ao cliente o download? Eu li vários tópicos semelhantes aqui, mas nenhum deles fornece a resposta que estou procurando.
Por favor, por favor, não poste respostas sugerindo que eu não deveria usar o ajax para isso ou que eu deveria redirecionar o navegador, porque nada disso é uma opção. Usar um formulário HTML simples também não é uma opção. O que eu preciso é mostrar uma caixa de diálogo de download para o cliente. Isso pode ser feito e como?
fonte
Respostas:
Crie um formulário, use o método POST, envie o formulário - não há necessidade de um iframe. Quando a página do servidor responder à solicitação, escreva um cabeçalho de resposta para o tipo MIME do arquivo e ele apresentará uma caixa de diálogo de download - já fiz isso várias vezes.
Você deseja o tipo de conteúdo de aplicativo / download - basta pesquisar como fornecer um download para qualquer idioma que esteja usando.
fonte
Não desista tão rapidamente, porque isso pode ser feito (em navegadores modernos) usando partes da FileAPI:
Aqui está a versão antiga usando jQuery.ajax. Pode manipular dados binários quando a resposta é convertida em uma sequência de algum conjunto de caracteres.
fonte
document.body.removeChild(a);
var blob =this.responce; /** if (typeof File === 'function') { try { blob = new File([this.response], filename, { type: type }); } catch (e) { /* Edge */ } } if (typeof blob === 'undefined') { blob = new Blob([this.response], { type: type }); } */
window.location.href = downloadUrl
vez dewindow.location = downloadUrl
Eu enfrentei o mesmo problema e resolvi-o com sucesso. Meu caso de uso é esse.
" Publique dados JSON no servidor e receba um arquivo do Excel. Esse arquivo do Excel é criado pelo servidor e retornado como resposta ao cliente. Faça o download dessa resposta como um arquivo com nome personalizado no navegador "
O snippet acima está apenas seguindo
Aqui, precisamos definir cuidadosamente algumas coisas no lado do servidor. Eu defini alguns cabeçalhos no Python Django HttpResponse. Você precisa configurá-los de acordo se usar outras linguagens de programação.
Desde que eu baixei xls (excel) aqui, ajustei contentType para acima de um. Você precisa configurá-lo de acordo com o seu tipo de arquivo. Você pode usar esta técnica para baixar qualquer tipo de arquivo.
fonte
Qual idioma do servidor você está usando? No meu aplicativo, posso baixar facilmente um arquivo de uma chamada AJAX, definindo os cabeçalhos corretos na resposta do PHP:
Definindo cabeçalhos do lado do servidor
Na verdade, isso 'redirecionará' o navegador para esta página de download, mas como @ahren já disse em seu comentário, ele não sairá da página atual.
É tudo sobre como definir os cabeçalhos corretos, por isso tenho certeza que você encontrará uma solução adequada para a linguagem do lado do servidor que estiver usando, se não for PHP.
Manipulando o Lado do Cliente de Resposta
Supondo que você já saiba como fazer uma chamada AJAX, no lado do cliente você executa uma solicitação AJAX para o servidor. O servidor gera um link a partir do qual esse arquivo pode ser baixado, por exemplo, o URL 'forward' para o qual você deseja apontar. Por exemplo, o servidor responde com:
Ao processar a resposta, você injeta um
iframe
no seu corpo e define oiframe
SRC para a URL que você acabou de receber assim (usando jQuery para facilitar o exemplo):Se você definiu os cabeçalhos corretos, como mostrado acima, o iframe forçará uma caixa de diálogo de download sem sair do navegador da página atual.
Nota
Adição extra em relação à sua pergunta; Eu acho que é melhor sempre retornar JSON ao solicitar coisas com a tecnologia AJAX. Depois de receber a resposta JSON, você pode decidir do lado do cliente o que fazer com ela. Talvez, por exemplo, mais tarde, você queira que o usuário clique em um link de download para o URL em vez de forçar o download diretamente, na sua configuração atual, você precisará atualizar o cliente e o servidor para fazer isso.
fonte
Para aqueles que procuram uma solução de uma perspectiva angular, isso funcionou para mim:
fonte
link.download = ""
resulta em um nome de arquivo guid aleatório elink.download = null
resulta em um arquivo chamado "null".INPUT
do elementoHTMLInputElement.files
. Consulte Os documentos MDN na entrada do arquivo para obter mais detalhes.Aqui está como eu consegui este trabalho https://stackoverflow.com/a/27563953/2845977
Resposta atualizada usando o download.js
fonte
success: function (response, status, request) { download(response, "filename.txt", "application/text"); }
Vejo que você já descobriu uma solução, no entanto, eu só queria adicionar algumas informações que podem ajudar alguém tentando conseguir a mesma coisa com grandes solicitações de POST.
Eu tive o mesmo problema há algumas semanas atrás, na verdade, não é possível obter um download "limpo" através do AJAX, o Filament Group criou um plugin jQuery que funciona exatamente como você já descobriu, é chamado de arquivo jQuery Baixe, no entanto, há uma desvantagem nessa técnica.
Se você estiver enviando grandes solicitações através do AJAX (digamos, arquivos + 1 MB), isso afetará negativamente a capacidade de resposta. Em conexões lentas com a Internet, você terá que esperar muito até que a solicitação seja enviada e também aguardar o download do arquivo. Não é como um instante "clique" => "pop-up" => "início do download". É mais como "clique" => "aguarde até que os dados sejam enviados" => "aguarde a resposta" => "download start", o que faz com que o arquivo apareça dobrar de tamanho, porque você terá que aguardar o envio da solicitação através do AJAX e recupere-o como um arquivo para download.
Se você estiver trabalhando com arquivos pequenos <1 MB, não perceberá isso. Mas, como descobri no meu próprio aplicativo, para tamanhos de arquivo maiores, é quase insuportável.
Meu aplicativo permite que os usuários exportem imagens geradas dinamicamente, essas imagens são enviadas através de solicitações POST no formato base64 para o servidor (é a única maneira possível), processadas e enviadas de volta aos usuários na forma de arquivos .png, .jpg, base64 seqüências de caracteres para imagens + 1 MB são enormes, forçando os usuários a esperar mais do que o necessário para o arquivo iniciar o download. Em conexões lentas com a Internet, pode ser realmente irritante.
Minha solução para isso foi gravar temporariamente o arquivo no servidor, assim que estiver pronto, gerar dinamicamente um link para o arquivo na forma de um botão que muda entre os estados "Aguarde ..." e "Download" e, ao mesmo tempo, Na hora, imprima a imagem base64 em uma janela pop-up para que os usuários possam "clicar com o botão direito" e salvá-la. Isso torna todo o tempo de espera mais suportável para os usuários e também acelera as coisas.
Atualização 30 de setembro de 2014:
Faça o download do exemplo de script:
Sei que isso está muito além do que o OP pediu, mas achei que seria bom atualizar minha resposta com minhas descobertas. Quando eu estava procurando soluções para o meu problema, li muitos tópicos "Download de dados do AJAX POST" que não me deram a resposta que eu estava procurando, espero que essas informações ajudem alguém que deseja obter algo assim.
fonte
jQuery File Download
único me redireciona para o URL. Eu chamo-lhe assim:jQuery.download("api/ide/download-this-file.php", {filePath: path2Down}, "POST");
.Quero apontar algumas dificuldades que surgem ao usar a técnica na resposta aceita, ou seja, ao usar um formulário:
Você não pode definir cabeçalhos na solicitação. Se o seu esquema de autenticação envolver cabeçalhos, um Json-Web-Token passado no cabeçalho de Autorização, você terá que encontrar outra maneira de enviá-lo, por exemplo, como um parâmetro de consulta.
Você não pode realmente dizer quando a solicitação foi concluída. Bem, você pode usar um cookie que é definido na resposta, como feito por jquery.fileDownload , mas é MUITO perfeito. Ele não funcionará para solicitações simultâneas e será interrompido se uma resposta nunca chegar.
Se o servidor responder com um erro, o usuário será redirecionado para a página de erro.
Você pode usar apenas os tipos de conteúdo suportados por um formulário . O que significa que você não pode usar JSON.
Acabei usando o método de salvar o arquivo no S3 e enviar uma URL pré-assinada para obter o arquivo.
fonte
Para aqueles que procuram uma abordagem mais moderna, você pode usar o
fetch API
. O exemplo a seguir mostra como baixar um arquivo de planilha. Isso é feito facilmente com o seguinte código.Acredito que essa abordagem seja muito mais fácil de entender do que outras
XMLHttpRequest
soluções. Além disso, possui uma sintaxe semelhante àjQuery
abordagem, sem a necessidade de adicionar bibliotecas adicionais.Obviamente, eu recomendaria verificar em qual navegador você está desenvolvendo, pois essa nova abordagem não funcionará no IE. Você pode encontrar a lista completa de compatibilidade do navegador no seguinte [link] [1].
Importante : Neste exemplo, estou enviando uma solicitação JSON para um servidor atendendo ao determinado
url
. Issourl
deve ser definido, no meu exemplo, estou assumindo que você conhece esta parte. Além disso, considere os cabeçalhos necessários para que sua solicitação funcione. Como estou enviando um JSON, devo adicionar oContent-Type
cabeçalho e configurá-loapplication/json; charset=utf-8
como, para informar ao servidor o tipo de solicitação que ele receberá.fonte
Aqui está minha solução usando um formulário oculto temporário.
Observe que eu uso massivamente o JQuery, mas você pode fazer o mesmo com o JS nativo.
fonte
Como já foi dito, você pode criar e enviar um formulário para fazer o download por meio de uma solicitação POST. No entanto, você não precisa fazer isso manualmente.
Uma biblioteca realmente simples para fazer exatamente isso é o jquery.redirect . Ele fornece uma API semelhante ao
jQuery.post
método padrão :fonte
Esta é uma pergunta de 3 anos, mas eu tive o mesmo problema hoje. Procurei sua solução editada, mas acho que ela pode sacrificar o desempenho, pois precisa fazer uma solicitação dupla. Portanto, se alguém precisar de outra solução que não implique em chamar o serviço duas vezes, é assim que eu fiz:
Este formulário é usado apenas para chamar o serviço e evitar o uso de um window.location (). Depois disso, basta enviar um formulário a partir do jquery para chamar o serviço e obter o arquivo. É bem simples, mas dessa maneira você pode fazer um download usando um POST . Agora que isso poderia ser mais fácil se o serviço para o qual você está ligando for um GET , mas esse não é o meu caso.
fonte
Eu usei este FileSaver.js . No meu caso com arquivos csv, fiz isso (em coffescript):
Para os casos mais complicados, os dados devem ser processados corretamente. Sob o capô, o FileSaver.js implementa a mesma abordagem da resposta de Jonathan Amend .
fonte
consulte: http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/ ele retornará um blob como resposta, que poderá ser colocado no salva-arquivos
fonte
Para que Jonathan Amends responda ao trabalho no Edge, fiz as seguintes alterações:
para isso
Eu preferia ter postado isso como um comentário, mas não tenho reputação suficiente para isso
fonte
Aqui está minha solução, reunida de diferentes fontes: Implementação do lado do servidor:
Implementação do lado do cliente (usando jquery):
fonte
existe outra solução para baixar uma página da web no ajax. Mas estou me referindo a uma página que deve primeiro ser processada e depois baixada.
Primeiro, você precisa separar o processamento da página do download dos resultados.
1) Apenas os cálculos da página são feitos na chamada ajax.
Espero que esta solução possa ser útil para muitos, como foi para mim.
fonte
Se a resposta for um buffer de matriz , tente isso no evento onsuccess no Ajax:
fonte
Abaixo está minha solução para baixar vários arquivos, dependendo de uma lista que consiste em alguns IDs e procurando no banco de dados, os arquivos serão determinados e prontos para download - se houver. Estou chamando a ação C # MVC para cada arquivo usando o Ajax.
E sim, como outros disseram, é possível fazer isso no jQuery Ajax. Fiz isso com sucesso no Ajax e estou sempre enviando a resposta 200.
Então, esta é a chave:
E este é o meu código:
Então chamando:
C # MVC:
Desde que você retorne a resposta 200, o sucesso no Ajax pode funcionar com ele, você pode verificar se o arquivo realmente existe ou não, pois a linha abaixo nesse caso seria falsa e você pode informar o usuário sobre isso:
fonte
Eu precisava de uma solução semelhante à do @ alain-cruz, mas no nuxt / vue com vários downloads. Eu sei que os navegadores bloqueiam vários downloads de arquivos e também tenho uma API que retorna um conjunto de dados formatados em csv. Se alguém puder me ajudar a melhorar isso, seria ótimo, mas está funcionando para mim até agora.
A API retorna:
page.vue:
fonte