J'ai une webapp d'une seule page basée sur jquery. Il communique avec un service Web RESTful via des appels AJAX.
J'essaie d'accomplir ce qui suit:
- Soumettez un POST contenant des données JSON à une URL REST.
- Si la demande spécifie une réponse JSON, alors JSON est renvoyé.
- Si la demande spécifie une réponse PDF / XLS / etc, un fichier binaire téléchargeable est renvoyé.
J'ai 1 & 2 travaillant maintenant, et l'application client jquery affiche les données renvoyées dans la page Web en créant des éléments DOM basés sur les données JSON. J'ai également le n ° 3 qui fonctionne du point de vue du service Web, ce qui signifie qu'il créera et renverra un fichier binaire s'il reçoit les paramètres JSON corrects. Mais je ne suis pas sûr de la meilleure façon de traiter # 3 dans le code javascript du client.
Est-il possible de récupérer un fichier téléchargeable à partir d'un appel ajax comme celui-ci? Comment faire pour que le navigateur télécharge et enregistre le fichier?
$.ajax({
type: "POST",
url: "/services/test",
contentType: "application/json",
data: JSON.stringify({category: 42, sort: 3, type: "pdf"}),
dataType: "json",
success: function(json, status){
if (status != "success") {
log("Error loading data");
return;
}
log("Data loaded!");
},
error: function(result, status, err) {
log("Error loading data");
return;
}
});
Le serveur répond avec les en-têtes suivants:
Content-Disposition:attachment; filename=export-1282022272283.pdf
Content-Length:5120
Content-Type:application/pdf
Server:Jetty(6.1.11)
Une autre idée est de générer le PDF et de le stocker sur le serveur et de renvoyer le JSON qui inclut une URL vers le fichier. Ensuite, lancez un autre appel dans le gestionnaire de réussite ajax pour faire quelque chose comme ceci:
success: function(json,status) {
window.location.href = json.url;
}
Mais cela signifie que je devrais faire plusieurs appels au serveur, et mon serveur devrait créer des fichiers téléchargeables, les stocker quelque part, puis nettoyer périodiquement cette zone de stockage.
Il doit y avoir un moyen plus simple d'accomplir cela. Des idées?
EDIT: Après avoir examiné les documents pour $ .ajax, je vois que la réponse dataType ne peut être que l'un xml, html, script, json, jsonp, text
, donc je suppose qu'il n'y a aucun moyen de télécharger directement un fichier à l'aide d'une demande ajax, à moins que j'incorpore le fichier binaire en utilisant Schéma d'URI de données comme suggéré dans la réponse @VinayC (ce qui n'est pas quelque chose que je veux faire).
Je suppose donc que mes options sont les suivantes:
N'utilisez pas ajax et soumettez plutôt un post de formulaire et intégrez mes données JSON dans les valeurs du formulaire. Aurait probablement besoin de jouer avec des iframes cachés et autres.
N'utilisez pas ajax et convertissez plutôt mes données JSON en une chaîne de requête pour créer une demande GET standard et définissez window.location.href sur cette URL. Peut-être besoin d'utiliser event.preventDefault () dans mon gestionnaire de clics pour empêcher le navigateur de changer à partir de l'URL de l'application.
Utilisez mon autre idée ci-dessus, mais améliorée avec des suggestions de la réponse @naikus. Soumettez la demande AJAX avec un paramètre qui permet au service Web de savoir que cela est appelé via un appel ajax. Si le service Web est appelé à partir d'un appel ajax, renvoyez simplement JSON avec une URL vers la ressource générée. Si la ressource est appelée directement, renvoyez le fichier binaire réel.
Plus j'y pense, plus j'aime la dernière option. De cette façon, je peux récupérer des informations sur la demande (temps de génération, taille du fichier, messages d'erreur, etc.) et je peux agir sur ces informations avant de démarrer le téléchargement. L'inconvénient est une gestion supplémentaire des fichiers sur le serveur.
D'autres moyens d'y parvenir? Y a-t-il des avantages / inconvénients à ces méthodes que je devrais connaître?
la source
url = 'http://localhost/file.php?file='+ $('input').val(); window.open(url);
La manière simple d'obtenir les mêmes résultats. Mettez l'en-tête dans le fichier php. Pas besoin d'envoyer un ajax ou d'obtenir des demandesRéponses:
La solution de letronje ne fonctionne que pour des pages très simples.
document.body.innerHTML +=
prend le texte HTML du corps, ajoute l'iframe HTML et définit le innerHTML de la page sur cette chaîne. Cela supprimera, entre autres, toutes les liaisons d'événements de votre page. Créez un élément et utilisez-le à laappendChild
place.Ou en utilisant jQuery
Ce que cela fait réellement: effectuer une publication dans /create_binary_file.php avec les données dans la variable postData; si cette publication se termine avec succès, ajoutez une nouvelle iframe au corps de la page. L'hypothèse est que la réponse de /create_binary_file.php inclura une valeur 'url', qui est l'URL à partir de laquelle le fichier PDF / XLS / etc généré peut être téléchargé. L'ajout d'un iframe à la page qui fait référence à cette URL entraînera le navigateur pour promouvoir l'utilisateur à télécharger le fichier, en supposant que le serveur Web a la configuration de type MIME appropriée.
la source
+=
et je mettrai à jour mon application en conséquence. Merci!Resource interpreted as Document but transferred with MIME type application/pdf
. Ensuite, il m'avertit également que le fichier peut être dangereux. Si je visite le retData.url directement, aucun avertissement ou problème.J'ai joué avec une autre option qui utilise des blobs. J'ai réussi à l'obtenir pour télécharger des documents texte, et j'ai téléchargé des PDF (cependant ils sont corrompus).
En utilisant l'API blob, vous pourrez effectuer les opérations suivantes:
Il s'agit d'IE 10+, Chrome 8+, FF 4+. Voir https://developer.mozilla.org/en-US/docs/Web/API/URL.createObjectURL
Il télécharge uniquement le fichier dans Chrome, Firefox et Opera. Cela utilise un attribut de téléchargement sur la balise d'ancrage pour forcer le navigateur à le télécharger.
la source
click
:window.URL.revokeObjectURL(link.href);
Je connais ce genre de vieux, mais je pense avoir trouvé une solution plus élégante. J'ai eu exactement le même problème. Le problème que je rencontrais avec les solutions suggérées était qu'elles nécessitaient toutes l'enregistrement du fichier sur le serveur, mais je ne voulais pas enregistrer les fichiers sur le serveur, car cela introduisait d'autres problèmes (sécurité: le fichier était alors accessible par utilisateurs non authentifiés, nettoyage: comment et quand vous débarrasser des fichiers). Et comme vous, mes données étaient des objets JSON imbriqués complexes qui seraient difficiles à mettre dans un formulaire.
J'ai créé deux fonctions serveur. Le premier a validé les données. S'il y avait une erreur, elle serait retournée. Si ce n'était pas une erreur, j'ai renvoyé tous les paramètres sérialisés / encodés sous forme de chaîne base64. Ensuite, sur le client, j'ai un formulaire qui n'a qu'une seule entrée cachée et publie sur une deuxième fonction serveur. J'ai défini l'entrée masquée sur la chaîne base64 et soumis le format. La deuxième fonction serveur décode / désérialise les paramètres et génère le fichier. Le formulaire pourrait être soumis à une nouvelle fenêtre ou à un iframe sur la page et le fichier s'ouvrira.
Il y a un peu plus de travail et peut-être un peu plus de traitement, mais dans l'ensemble, je me sentais beaucoup mieux avec cette solution.
Le code est en C # / MVC
sur le client
la source
Il existe un moyen plus simple de créer un formulaire et de le publier, cela risque de réinitialiser la page si le type de mime de retour est quelque chose qu'un navigateur ouvrirait, mais pour csv et tel, c'est parfait
L'exemple nécessite un soulignement et jquery
Pour des choses comme html, texte et autres, assurez-vous que le mimetype est quelque chose comme application / octet-stream
code php
la source
Bref, il n'y a pas de moyen plus simple. Vous devez faire une autre demande de serveur pour afficher le fichier PDF. Cependant, il existe peu d'alternatives mais elles ne sont pas parfaites et ne fonctionneront pas sur tous les navigateurs:
la source
Content-Disposition: attachment;filename="file.txt"
), mais je veux vraiment essayer cette approche la prochaine fois. J'avais déjà utilisé desURI
données pour des miniatures, mais je n'ai jamais pensé à les utiliser pour les téléchargements - merci de partager ce nugget.Cela fait un moment que cette question n'a pas été posée mais j'ai eu le même défi et je veux partager ma solution. Il utilise des éléments des autres réponses mais je n'ai pas pu le trouver dans son intégralité. Il n'utilise pas de formulaire ou d'iframe mais nécessite une paire de requêtes post / get. Au lieu d'enregistrer le fichier entre les demandes, il enregistre les données de publication. Cela semble à la fois simple et efficace.
client
serveur
la source
la source
Pas entièrement une réponse au message d'origine, mais une solution rapide et sale pour publier un objet json sur le serveur et générer dynamiquement un téléchargement.
Côté client jQuery:
.. puis décodage de la chaîne json sur le côté serveur et définition des en-têtes à télécharger (exemple PHP):
la source
Je pense que la meilleure approche est d'utiliser une combinaison, votre deuxième approche semble être une solution élégante où les navigateurs sont impliqués.
Donc, selon la façon dont l'appel est effectué. (que ce soit un navigateur ou un appel de service Web), vous pouvez utiliser une combinaison des deux, avec l'envoi d'une URL au navigateur et l'envoi de données brutes à tout autre client de service Web.
la source
Je suis réveillé depuis deux jours maintenant pour essayer de comprendre comment télécharger un fichier en utilisant jquery avec un appel ajax. Tout le soutien que j'ai obtenu n'a pas pu aider ma situation jusqu'à ce que j'essaye.
Côté client
Du côté serveur
Bonne chance.
la source
Je l'ai trouvé quelque part il y a longtemps et cela fonctionne parfaitement!
la source
Une autre approche au lieu d'enregistrer le fichier sur le serveur et de le récupérer, consiste à utiliser .NET 4.0+ ObjectCache avec une courte expiration jusqu'à la deuxième action (date à laquelle il peut être définitivement vidé). La raison pour laquelle je veux utiliser JQuery Ajax pour faire l'appel, c'est qu'il est asynchrone. La construction de mon fichier PDF dynamique prend un peu de temps et j'affiche une boîte de dialogue de spinner occupée pendant ce temps (cela permet également de faire d'autres travaux). L'approche consistant à utiliser les données renvoyées dans le "succès:" pour créer un blob ne fonctionne pas de manière fiable. Cela dépend du contenu du fichier PDF. Il est facilement corrompu par les données de la réponse, s'il n'est pas complètement textuel, c'est tout ce que Ajax peut gérer.
la source
Solution
La pièce jointe Content-Disposition semble fonctionner pour moi:
solution de contournement
application / octet-stream
Il m'arrivait quelque chose de similaire avec un JSON, pour moi côté serveur, je mettais l'en-tête sur self.set_header ("Content-Type", " application / json ") mais quand je l'ai changé en:
Il l'a automatiquement téléchargé.
Sachez également que pour que le fichier conserve le suffixe .json, vous en aurez besoin dans l'en-tête du nom de fichier:
la source
Avec HTML5, vous pouvez simplement créer une ancre et cliquer dessus. Il n'est pas nécessaire de l'ajouter au document en tant qu'enfant.
Terminé.
Si vous voulez avoir un nom spécial pour le téléchargement, passez-le simplement dans l'
download
attribut:la source