POST to server, recevoir des PDF, livrer à l’utilisateur avec jQuery

J’ai un lien sur lequel l’utilisateur clique pour obtenir un PDF. Dans jQuery, je crée un appel ajax POST au serveur pour obtenir le PDF. Le PDF me parvient avec les en-têtes de contenu corrects, etc., qui permettent normalement au navigateur d’ouvrir le plug-in Reader ou d’autoriser l’utilisateur à enregistrer le PDF.

Comme je reçois le PDF avec un appel ajax, je ne sais pas trop quoi faire avec les données que je reçois dans le rappel OnSuccess. Comment est-ce que je peux donner les données que je reçois au navigateur et lui permettre de faire son choix par défaut avec la réponse PDF?

Vous n’avez pas besoin de jQuery du tout. Envoyez simplement votre POST via un formulaire normalement et côté serveur, ajoutez l’en-tête HTTP

 Content-Disposition: attachment; filename="whatever.pdf" 

Le navigateur fera sa chose par défaut.

Sinon, vous pouvez le faire si vous voulez faire plus attention au signalement d’erreurs pouvant survenir lors de la génération de fichiers PDF. POST vos parameters sur votre serveur avec jQuery. Sur le serveur, générez le contenu binary et mettez-le en cache quelques minutes, accessible via une clé que vous avez insérée dans la session de l’utilisateur, et renvoyez une réponse Ajax “réussie” à votre page (ou, en cas d’erreur, renvoyez une “erreur” réponse). Si la page récupère une réponse réussie, elle peut immédiatement faire quelque chose comme:

 window.location = "/get/my/pdf"; 

Le serveur renvoie alors le contenu PDF mis en cache. Veillez à inclure l’en-tête Content-Disposition, comme ci-dessus.

Jetez un oeil sur – Plugin jQuery pour demander des téléchargements de fichiers de type Ajax

L’ensemble du plugin ne contient qu’environ 30 lignes de code (y compris les commentaires).

L’appel est assez similaire à l’appel jquery ajax.

 $.download('/export.php','filename=myPDF&format=pdf&content=' + pdfData ); 

Bien sûr, vous devez définir les en-têtes content-type et Content-Disposition du côté serveur, comme vous le feriez pour un tel téléchargement.

En java je ferais quelque chose comme ça

 response.setContentType("application/pdf"); response.setHeader("Content-Disposition", "attachment; filename="exported.pdf"); 

La réponse mentionnant “Plugin jQuery pour demander des téléchargements de fichiers de type Ajax” m’a permis de me diriger dans la bonne direction, mais cela ne fonctionnait pas entièrement dans ma situation car j’ai un object complexe et un tableau d’objects à transmettre. filtrer les données. Je pensais que je partagerais mon code au cas où quelqu’un d’autre se retrouverait dans cette situation.

 $.download = function (url, data, method) { if (url && data) { //convert the data object into input HTML fields var inputs = ''; var convertToInput = function (key, keyStr, obj) { if (typeof obj === 'undefined') { return; } else if (typeof obj === "object") { for (var innerKey in obj) { if (obj.hasOwnProperty(innerKey)) { var innerKeyStr = ''; if (keyStr === '') { innerKeyStr = innerKey.toSsortingng(); } else { innerKeyStr = keyStr + "[" + innerKey.toSsortingng() + "]"; } convertToInput(innerKey, innerKeyStr, obj[innerKey]); } } return; } else if ($.isArray(obj)) { obj.forEach(function (item) { convertToInput(key, keyStr + "[]", item); }); return; } inputs += ""; }; convertToInput(null, '', data); //send request jQuery('
' + inputs + '
').appendTo('body').submit().remove(); }; }; $.download('/api/search?format=csv', searchData, 'POST');

Cela ne fait probablement pas beaucoup de différence, mais pour fournir un peu de contexte, j’ai une interface utilisateur javascript et knockout qui appelle WebAPI, MVC4 et nHibernate. La partie ‘format = csv’ de la chaîne de requête déclenche un MediaTypeFormatter pour convertir les modèles renvoyés en un type de fichier CSV. Si je le laisse, je récupère les modèles de l’API et peut afficher une grid Slick.

J’ai eu le même problème mais en plus, utilisez un service RESTFUL webservice pour cela et disposez d’un object de données complexe que je dois poster.

Ma solution: comme le plugin jQuery, je construis un formulaire temporaire et le soumets. Mais j’envoie l’object de données en tant que paramètre avec le contenu json (j’utilise ici AngularJS mais il devrait aussi fonctionner avec jQuery.param() .

Javascript:

 $('
' + "" + '
').appendTo('body').submit().remove();

du côté serveur, nous utilisons un service CXF REST Service avec un fournisseur JACKSON :

Config de spring:

          

dans le contrôleur, j’ai extrait le paramètre et l’a reconverti en Java Pojo:

 package de.controller; import javax.ws.rs.Consumes; import javax.ws.rs.FormParam; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.codehaus.jackson.map.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; @Path(Constants.PRINT_PATH) @Consumes({ MediaType.APPLICATION_JSON, "application/x-www-form-urlencoded"}) @Produces("application/pdf; charset=UTF-8") public class PrintRestController { @Autowired private PrintService printService; @POST @Produces("application/pdf") @Path("/pdf") public Response getPDF(@FormParam("data") Ssortingng data) { return printService.getPDF(json2Versicherung(data)); } private Versicherung json2Versicherung(Ssortingng data) { Versicherung lVersicherung = null; try { ObjectMapper mapper = new ObjectMapper(); lVersicherung = mapper.readValue(data, Versicherung.class); } catch(Exception e) { LOGGER.error("PrintRestController.json2Versicherung() error", e); } return lVersicherung; } } 

dans PrintService, je construis le fichier binary pdf et la réponse:

 @Override public Response getPDF(Versicherung pVersicherung) { byte[] result = ... //build the pdf from what ever ResponseBuilder response = Response.ok((Object) result); response.header("Content-Disposition", "inline; filename=mypdf.pdf"); return response.build(); } 

Cette solution fonctionne sur tous les navigateurs (même pour IE9, qui ne peut pas gérer les URL de données), sur les tablettes et les smartphones, et ne pose aucun problème avec les popupblockers.

Le plug-in jQuery pour demander le téléchargement de fichiers de type Ajax consiste essentiellement à créer un formulaire, en ajoutant les données de publication en tant que champ caché, en l’ajoutant au corps de la page, en le soumettant et en le supprimant.

Dans mon cas, je n’avais pas de formulaire, mais seulement une partie des données à afficher. Cela a fait pour la solution suivante. Du côté du serveur, je peux obtenir les données en lisant simplement le paramètre “data” de la requête et en le décodant par URI.

 function postAndDownload(url, data) { encodedData = encodeURIComponent(data); $("
") .attr("action", url) .attr("method", "post") .append( $("input") .attr("type", "hidden") .attr("name", "data") .attr("value", encodedData) ) .appendTo("body") .submit() .remove(); };

Je n’arrive pas à comprendre pourquoi vous voulez une requête ajax à une URL de téléchargement de fichier! Mais si c’est plus comme si le client lui-même génère du contenu à télécharger, utilisez un uri de données. Fonctionne parfaitement pour Chrome et Firefox 20+. Safari et IE non! Si Flash est autorisé, vous pouvez utiliser le téléchargeur.

Ah après avoir lu votre code, je vois que vous voulez envoyer un tas de parameters. Eh bien, à moins que la chaîne de requête ne devienne trop longue (IE8- a une limite de 2083), pourquoi ne pas simplement utiliser une ancre avec une URL correcte?

  $('a.export-csv').click( function (evt){ linkEl.attr('href','/export?' + encodeURIComponent(formQuerySsortingng())); return true; }); 

Ce qui précède vous permet de modifier l’URL avant que l’événement par défaut (le clic) se produise.

Je pense que le mieux sera de créer un fichier PDF temporaire dans le dossier des téléchargements, puis de charger le fichier en utilisant des fenêtres pop-up avec un iframe. Le chrome le chargera instantanément, mais je suppose que pour d’autres mais encore une fois, vous pouvez utiliser FlashPaper aussi 🙂