J'ai une application javascript qui envoie des requêtes ajax POST à une certaine URL. La réponse peut être une chaîne JSON ou un fichier (en tant que pièce jointe). Je peux facilement détecter Content-Type et Content-Disposition dans mon appel ajax, mais une fois que je détecte que la réponse contient un fichier, comment proposer au client de le télécharger? J'ai lu un certain nombre de sujets similaires ici, mais aucun d'entre eux ne fournit la réponse que je recherche.
S'il vous plaît, s'il vous plaît, ne postez pas de réponses suggérant que je ne devrais pas utiliser ajax pour cela ou que je devrais rediriger le navigateur, car rien de tout cela n'est une option. L'utilisation d'un formulaire HTML simple n'est pas non plus une option. Ce dont j'ai besoin, c'est d'afficher une boîte de dialogue de téléchargement au client. Est-ce possible de le faire et comment?
la source
Réponses:
Créez un formulaire, utilisez la méthode POST, soumettez le formulaire - il n'y a pas besoin d'un iframe. Lorsque la page du serveur répond à la demande, écrivez un en-tête de réponse pour le type MIME du fichier, et il présentera une boîte de dialogue de téléchargement - je l'ai fait plusieurs fois.
Vous voulez un type d'application / de téléchargement de contenu - recherchez simplement comment fournir un téléchargement pour la langue que vous utilisez.
la source
N'abandonnez pas si vite, car cela peut être fait (dans les navigateurs modernes) en utilisant des parties de FileAPI:
Voici l'ancienne version utilisant jQuery.ajax. Il pourrait altérer les données binaires lorsque la réponse est convertie en une chaîne d'un jeu de caractères.
la source
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
au lieu dewindow.location = downloadUrl
J'ai fait face au même problème et l'ai résolu avec succès. Mon cas d'utilisation est le suivant.
" Publiez les données JSON sur le serveur et recevez un fichier Excel. Ce fichier Excel est créé par le serveur et renvoyé comme réponse au client. Téléchargez cette réponse sous forme de fichier avec un nom personnalisé dans le navigateur "
L'extrait ci-dessus ne fait que suivre
Ici, nous devons soigneusement définir quelques éléments côté serveur. J'ai défini quelques en-têtes dans Python Django HttpResponse. Vous devez les définir en conséquence si vous utilisez d'autres langages de programmation.
Depuis que je télécharge xls (excel) ici, j'ai ajusté contentType au dessus. Vous devez le définir en fonction de votre type de fichier. Vous pouvez utiliser cette technique pour télécharger tout type de fichiers.
la source
Quelle langue côté serveur utilisez-vous? Dans mon application, je peux facilement télécharger un fichier à partir d'un appel AJAX en définissant les en-têtes corrects dans la réponse de PHP:
Définition des en-têtes côté serveur
En fait, cela «redirigera» le navigateur vers cette page de téléchargement, mais comme @ahren l'a déjà dit dans son commentaire, il ne s'éloignera pas de la page actuelle.
Il s'agit de définir les en-têtes corrects, donc je suis sûr que vous trouverez une solution appropriée pour le langage côté serveur que vous utilisez si ce n'est pas PHP.
Gestion du côté client de réponse
En supposant que vous savez déjà comment passer un appel AJAX, du côté client, vous exécutez une demande AJAX vers le serveur. Le serveur génère ensuite un lien à partir duquel ce fichier peut être téléchargé, par exemple l'URL "de transfert" vers laquelle vous souhaitez pointer. Par exemple, le serveur répond avec:
Lors du traitement de la réponse, vous injectez un
iframe
dans votre corps et définissez leiframe
SRC de l'URL que vous venez de recevoir comme ceci (en utilisant jQuery pour la facilité de cet exemple):Si vous avez défini les en-têtes corrects comme indiqué ci-dessus, l'iframe forcera une boîte de dialogue de téléchargement sans éloigner le navigateur de la page actuelle.
Remarque
Ajout supplémentaire par rapport à votre question; Je pense qu'il est préférable de toujours retourner JSON lorsque vous demandez des trucs avec la technologie AJAX. Après avoir reçu la réponse JSON, vous pouvez ensuite décider côté client quoi en faire. Par exemple, vous souhaiterez peut-être plus tard que l'utilisateur clique sur un lien de téléchargement vers l'URL au lieu de forcer le téléchargement directement, dans votre configuration actuelle, vous devrez mettre à jour le client et le serveur pour ce faire.
la source
Pour ceux qui recherchent une solution d'un point de vue angulaire, cela a fonctionné pour moi:
la source
link.download = ""
entraîne un nom de fichier guid aléatoire etlink.download = null
un fichier nommé "null".INPUT
élémentHTMLInputElement.files
. Voir Les documents MDN sur l'entrée de fichier pour plus de détails.Voici comment j'ai obtenu ce fonctionnement https://stackoverflow.com/a/27563953/2845977
Réponse mise à jour à l'aide de download.js
la source
success: function (response, status, request) { download(response, "filename.txt", "application/text"); }
Je vois que vous avez déjà trouvé une solution, mais je voulais juste ajouter quelques informations qui pourraient aider quelqu'un à essayer de faire la même chose avec de grandes demandes POST.
J'ai eu le même problème il y a quelques semaines, en effet, il n'est pas possible de réaliser un téléchargement "propre" via AJAX, le Filament Group a créé un plugin jQuery qui fonctionne exactement comme vous l'avez déjà découvert, il s'appelle jQuery File Téléchargez cependant il y a un inconvénient à cette technique.
Si vous envoyez de grosses demandes via AJAX (par exemple, des fichiers + 1 Mo), cela aura un impact négatif sur la réactivité. Dans les connexions Internet lentes, vous devrez attendre beaucoup jusqu'à ce que la demande soit envoyée et également attendre le téléchargement du fichier. Ce n'est pas comme un "clic" instantané => "popup" => "début de téléchargement". Cela ressemble plus à "cliquer" => "attendre que les données soient envoyées" => "attendre la réponse" => "démarrer le téléchargement" ce qui fait apparaître le fichier deux fois sa taille car vous devrez attendre que la demande soit envoyée via AJAX et récupérez-le sous forme de fichier téléchargeable.
Si vous travaillez avec des fichiers de petite taille <1 Mo, vous ne le remarquerez pas. Mais comme je l'ai découvert dans ma propre application, pour des fichiers plus volumineux, c'est presque insupportable.
Mon application permet aux utilisateurs d'exporter des images générées dynamiquement, ces images sont envoyées via des requêtes POST au format base64 au serveur (c'est le seul moyen possible), puis traitées et renvoyées aux utilisateurs sous forme de fichiers .png, .jpg, base64 les chaînes d'images + 1 Mo sont énormes, ce qui oblige les utilisateurs à attendre plus que nécessaire pour que le fichier commence à télécharger. Dans les connexions Internet lentes, cela peut être très ennuyeux.
Ma solution a été d'écrire temporairement le fichier sur le serveur, une fois qu'il est prêt, de générer dynamiquement un lien vers le fichier sous la forme d'un bouton qui change entre les états "Veuillez patienter ..." et "Télécharger" et en même temps temps, imprimez l'image base64 dans une fenêtre contextuelle d'aperçu afin que les utilisateurs puissent "cliquer avec le bouton droit" et l'enregistrer. Cela rend tout le temps d'attente plus supportable pour les utilisateurs et accélère également les choses.
Mise à jour du 30 septembre 2014:
Télécharger l'exemple de script:
Je sais que c'est bien au-delà de ce que le PO a demandé, mais j'ai pensé qu'il serait bon de mettre à jour ma réponse avec mes conclusions. Lorsque je cherchais des solutions à mon problème, j'ai lu beaucoup de threads "Télécharger à partir des données AJAX POST" qui ne m'ont pas donné la réponse que je cherchais, j'espère que ces informations aideront quelqu'un qui cherche à réaliser quelque chose comme ça.
la source
jQuery File Download
seul me redirige vers l'url. Je l' appelle comme ceci:jQuery.download("api/ide/download-this-file.php", {filePath: path2Down}, "POST");
.Je tiens à souligner certaines difficultés qui surviennent lors de l'utilisation de la technique dans la réponse acceptée, c'est-à-dire en utilisant un formulaire de post:
Vous ne pouvez pas définir d'en-têtes sur la demande. Si votre schéma d'authentification implique des en-têtes, un Json-Web-Token passé dans l'en-tête d'autorisation, vous devrez trouver un autre moyen de l'envoyer, par exemple en tant que paramètre de requête.
Vous ne pouvez pas vraiment dire quand la demande est terminée. Eh bien, vous pouvez utiliser un cookie qui est défini sur la réponse, comme le fait jquery.fileDownload , mais c'est loin d'être parfait. Cela ne fonctionnera pas pour les demandes simultanées et il se cassera si une réponse n'arrive jamais.
Si le serveur répond avec une erreur, l'utilisateur sera redirigé vers la page d'erreur.
Vous ne pouvez utiliser que les types de contenu pris en charge par un formulaire . Ce qui signifie que vous ne pouvez pas utiliser JSON.
J'ai fini par utiliser la méthode d'enregistrement du fichier sur S3 et l'envoi d'une URL pré-signée pour obtenir le fichier.
la source
Pour ceux qui recherchent une approche plus moderne, vous pouvez utiliser le
fetch API
. L'exemple suivant montre comment télécharger un fichier de feuille de calcul. Cela se fait facilement avec le code suivant.Je pense que cette approche est beaucoup plus facile à comprendre que les autres
XMLHttpRequest
solutions. En outre, il a une syntaxe similaire à l'jQuery
approche, sans avoir besoin d'ajouter de bibliothèques supplémentaires.Bien sûr, je vous conseillerais de vérifier dans quel navigateur vous développez, car cette nouvelle approche ne fonctionnera pas sur IE. Vous pouvez trouver la liste complète de compatibilité du navigateur sur le [lien] [1] suivant.
Important : Dans cet exemple, j'envoie une demande JSON à un serveur écoutant le donné
url
. Celaurl
doit être réglé, sur mon exemple, je suppose que vous connaissez cette partie. Tenez également compte des en-têtes nécessaires au bon fonctionnement de votre demande. Étant donné que j'envoie un JSON, je dois ajouter l'en-Content-Type
tête et le définir surapplication/json; charset=utf-8
, afin d'indiquer au serveur le type de demande qu'il recevra.la source
Voici ma solution en utilisant un formulaire caché temporaire.
Notez que j'utilise massivement JQuery mais vous pouvez faire de même avec JS natif.
la source
Comme d'autres l'ont indiqué, vous pouvez créer et soumettre un formulaire à télécharger via une demande POST. Cependant, vous n'avez pas à le faire manuellement.
Une bibliothèque vraiment simple pour faire exactement cela est jquery.redirect . Il fournit une API similaire à la
jQuery.post
méthode standard :la source
C'est une question vieille de 3 ans mais j'ai eu le même problème aujourd'hui. J'ai regardé votre solution modifiée mais je pense qu'elle peut sacrifier les performances car elle doit faire une double demande. Donc, si quelqu'un a besoin d'une autre solution qui n'implique pas d'appeler le service deux fois, voici comment je l'ai fait:
Ce formulaire est juste utilisé pour appeler le service et éviter d'utiliser un window.location (). Après cela, il vous suffit de soumettre un formulaire à partir de jquery afin d'appeler le service et d'obtenir le fichier. C'est assez simple mais de cette façon, vous pouvez effectuer un téléchargement à l'aide d'un POST . Je pense maintenant que cela pourrait être plus facile si le service que vous appelez est un GET , mais ce n'est pas mon cas.
la source
J'ai utilisé ce FileSaver.js . Dans mon cas avec des fichiers csv, je l'ai fait (en coffescript):
Je pense que pour le cas le plus compliqué, les données doivent être traitées correctement. Sous le capot FileSaver.js met en œuvre la même approche que la réponse de Jonathan Amend .
la source
voir: http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/ il renverra un blob comme réponse, qui peut ensuite être mis dans l'économiseur de fichiers
la source
Pour obtenir la réponse de Jonathan Amends pour travailler dans Edge, j'ai apporté les modifications suivantes:
pour ça
J'aurais préféré poster ceci en commentaire mais je n'ai pas assez de réputation pour ça
la source
Voici ma solution, issue de différentes sources: Implémentation côté serveur:
Implémentation côté client (à l'aide de jquery):
la source
il existe une autre solution pour télécharger une page web en ajax. Mais je fais référence à une page qui doit d'abord être traitée puis téléchargée.
Vous devez d'abord séparer le traitement de la page du téléchargement des résultats.
1) Seuls les calculs de page sont effectués dans l'appel ajax.
J'espère que cette solution pourra être utile à beaucoup, comme elle l'a été pour moi.
la source
Si la réponse est un tampon de tableau , essayez ceci sous l'événement onsuccess dans Ajax:
la source
Ci-dessous, ma solution pour télécharger plusieurs fichiers en fonction d'une liste composée de certains identifiants et rechercher dans la base de données, les fichiers seront déterminés et prêts à être téléchargés - s'ils existent. J'appelle une action C # MVC pour chaque fichier utilisant Ajax.
Et oui, comme d'autres l'ont dit, il est possible de le faire dans jQuery Ajax. Je l'ai fait avec le succès de l'Ajax et j'envoie toujours une réponse 200.
Voici donc la clé:
Et voici mon code:
Appelant ensuite:
C # MVC:
Tant que vous renvoyez la réponse 200, le succès dans Ajax peut fonctionner avec, vous pouvez vérifier si le fichier existe réellement ou non car la ligne ci-dessous dans ce cas serait fausse et vous pouvez en informer l'utilisateur:
la source
J'avais besoin d'une solution similaire à celle de @ alain-cruz, mais en nuxt / vue avec plusieurs téléchargements. Je sais que les navigateurs bloquent plusieurs téléchargements de fichiers, et j'ai également une API qui renvoie un ensemble de données au format csv. J'allais utiliser JSZip au début, mais j'avais besoin du support IE, voici ma solution. Si quelqu'un peut m'aider à améliorer cela, ce serait formidable, mais cela fonctionne pour moi jusqu'à présent.
L'API renvoie:
page.vue:
la source