Ich habe eine jquery-basierte einseitige Webanwendung. Es kommuniziert mit einem RESTful-Webdienst über AJAX-Aufrufe.
Ich versuche Folgendes zu erreichen:
- Senden Sie einen POST, der JSON-Daten enthält, an eine REST-URL.
- Wenn die Anforderung eine JSON-Antwort angibt, wird JSON zurückgegeben.
- Wenn die Anforderung eine PDF / XLS / etc-Antwort angibt, wird eine herunterladbare Binärdatei zurückgegeben.
Ich habe 1 & 2 jetzt arbeiten, und die Client-Abfrage-App zeigt die zurückgegebenen Daten auf der Webseite an, indem sie DOM-Elemente basierend auf den JSON-Daten erstellt. Ich habe auch # 3 aus der Sicht des Webdienstes, was bedeutet, dass eine Binärdatei erstellt und zurückgegeben wird, wenn die richtigen JSON-Parameter angegeben werden. Ich bin mir jedoch nicht sicher, wie ich am besten mit # 3 im Client-Javascript-Code umgehen soll.
Ist es möglich, eine herunterladbare Datei von einem Ajax-Aufruf wie diesem zurückzubekommen? Wie kann ich den Browser dazu bringen, die Datei herunterzuladen und zu speichern?
$.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;
}
});
Der Server antwortet mit folgenden Headern:
Content-Disposition:attachment; filename=export-1282022272283.pdf
Content-Length:5120
Content-Type:application/pdf
Server:Jetty(6.1.11)
Eine andere Idee besteht darin, die PDF-Datei zu generieren, auf dem Server zu speichern und JSON zurückzugeben, das eine URL zur Datei enthält. Rufen Sie dann den Ajax Success Handler erneut auf, um Folgendes zu tun:
success: function(json,status) {
window.location.href = json.url;
}
Dies bedeutet jedoch, dass ich mehr als einen Anruf beim Server tätigen muss und mein Server herunterladbare Dateien erstellen, irgendwo speichern und dann diesen Speicherbereich regelmäßig bereinigen muss.
Es muss einen einfacheren Weg geben, dies zu erreichen. Ideen?
BEARBEITEN: Nachdem ich die Dokumente auf $ .ajax überprüft habe, sehe ich, dass der Antwortdatentyp nur einer von sein xml, html, script, json, jsonp, text
kann. Ich vermute, dass es keine Möglichkeit gibt, eine Datei mithilfe einer Ajax-Anforderung direkt herunterzuladen, es sei denn, ich binde die Binärdatei in using ein Daten-URI-Schema, wie in der @ VinayC-Antwort vorgeschlagen (was ich nicht tun möchte).
Ich denke also, meine Optionen sind:
Verwenden Sie nicht Ajax und senden Sie stattdessen einen Formularbeitrag und binden Sie meine JSON-Daten in die Formularwerte ein. Müsste wahrscheinlich mit versteckten Iframes und so weiter herumspielen.
Verwenden Sie nicht Ajax und konvertieren Sie stattdessen meine JSON-Daten in eine Abfragezeichenfolge, um eine Standard-GET-Anforderung zu erstellen und window.location.href auf diese URL zu setzen. Möglicherweise muss event.preventDefault () in meinem Klick-Handler verwendet werden, um zu verhindern, dass sich der Browser von der Anwendungs-URL ändert.
Verwenden Sie meine andere Idee oben, aber erweitert mit Vorschlägen aus der @ naikus-Antwort. Senden Sie eine AJAX-Anfrage mit einem Parameter, der den Webdienst darüber informiert, dass dies über einen Ajax-Aufruf aufgerufen wird. Wenn der Webdienst von einem Ajax-Aufruf aufgerufen wird, geben Sie JSON einfach mit einer URL an die generierte Ressource zurück. Wenn die Ressource direkt aufgerufen wird, geben Sie die eigentliche Binärdatei zurück.
Je mehr ich darüber nachdenke, desto mehr gefällt mir die letzte Option. Auf diese Weise kann ich Informationen über die Anforderung (Zeit zum Generieren, Dateigröße, Fehlermeldungen usw.) zurückerhalten und auf diese Informationen reagieren, bevor ich mit dem Download beginne. Der Nachteil ist die zusätzliche Dateiverwaltung auf dem Server.
Gibt es noch andere Möglichkeiten, dies zu erreichen? Gibt es Vor- und Nachteile dieser Methoden, die mir bekannt sein sollten?
quelle
url = 'http://localhost/file.php?file='+ $('input').val(); window.open(url);
Der einfache Weg, um die gleichen Ergebnisse zu erzielen. Setzen Sie den Header in PHP-Datei. Keine Notwendigkeit,Antworten:
Die Lösung von letronje funktioniert nur für sehr einfache Seiten.
document.body.innerHTML +=
Nimmt den HTML-Text des Körpers, hängt den Iframe-HTML-Code an und setzt das innerHTML der Seite auf diese Zeichenfolge. Dadurch werden unter anderem alle Ereignisbindungen auf Ihrer Seite gelöscht. Erstellen Sie ein Element und verwenden Sie esappendChild
stattdessen.Oder mit jQuery
Was dies tatsächlich bewirkt: Führen Sie einen Beitrag in /create_binary_file.php mit den Daten in der Variablen postData aus. Wenn dieser Beitrag erfolgreich abgeschlossen wurde, fügen Sie dem Hauptteil der Seite einen neuen Iframe hinzu. Es wird davon ausgegangen, dass die Antwort von /create_binary_file.php den Wert 'url' enthält. Dies ist die URL, von der die generierte PDF / XLS / etc-Datei heruntergeladen werden kann. Das Hinzufügen eines Iframes zu der Seite, die auf diese URL verweist, führt dazu, dass der Browser den Benutzer zum Herunterladen der Datei auffordert, vorausgesetzt, der Webserver verfügt über die entsprechende MIME-Typkonfiguration.
quelle
+=
und ich werde meine Anwendung entsprechend aktualisieren. Vielen Dank!Resource interpreted as Document but transferred with MIME type application/pdf
. Dann warnt es mich auch, dass die Datei gefährlich sein kann. Wenn ich die retData.url direkt besuche, keine Warnungen oder Probleme.Ich habe mit einer anderen Option herumgespielt, die Blobs verwendet. Ich habe es geschafft, Textdokumente herunterzuladen, und ich habe PDFs heruntergeladen (sie sind jedoch beschädigt).
Mit der Blob-API können Sie Folgendes tun:
Dies ist IE 10+, Chrome 8+, FF 4+. Siehe https://developer.mozilla.org/en-US/docs/Web/API/URL.createObjectURL
Die Datei wird nur in Chrome, Firefox und Opera heruntergeladen. Hierbei wird ein Download-Attribut für das Ankertag verwendet, um den Browser zum Herunterladen zu zwingen.
quelle
click
window.URL.revokeObjectURL(link.href);
Ich kenne diese Art von alt, aber ich denke, ich habe eine elegantere Lösung gefunden. Ich hatte genau das gleiche Problem. Das Problem, das ich mit den vorgeschlagenen Lösungen hatte, war, dass alle die Datei auf dem Server speichern mussten, aber ich wollte die Dateien nicht auf dem Server speichern, da dies andere Probleme mit sich brachte (Sicherheit: Auf die Datei konnte dann zugegriffen werden nicht authentifizierte Benutzer, Bereinigung: Wie und wann werden die Dateien entfernt? Und wie Sie waren meine Daten komplexe, verschachtelte JSON-Objekte, die sich nur schwer in ein Formular einfügen lassen.
Ich habe zwei Serverfunktionen erstellt. Der erste validierte die Daten. Wenn ein Fehler aufgetreten ist, wird er zurückgegeben. Wenn es kein Fehler war, habe ich alle Parameter zurückgegeben, die als base64-Zeichenfolge serialisiert / codiert wurden. Dann habe ich auf dem Client ein Formular, das nur eine versteckte Eingabe hat und an eine zweite Serverfunktion sendet. Ich setze die versteckte Eingabe auf die base64-Zeichenfolge und sende das Format. Die zweite Serverfunktion dekodiert / deserialisiert die Parameter und generiert die Datei. Das Formular kann an ein neues Fenster oder einen Iframe auf der Seite gesendet werden, und die Datei wird geöffnet.
Es ist ein bisschen mehr Arbeit und vielleicht ein bisschen mehr Verarbeitung erforderlich, aber insgesamt habe ich mich mit dieser Lösung viel besser gefühlt.
Code ist in C # / MVC
auf dem Client
quelle
Es gibt eine einfachere Möglichkeit, ein Formular zu erstellen und zu veröffentlichen. Dies birgt das Risiko, dass die Seite zurückgesetzt wird, wenn ein Browser den Typ "Return Mime" öffnen würde, aber für CSV und dergleichen ist er perfekt
Beispiel erfordert Unterstrich und Abfrage
Stellen Sie für Dinge wie HTML, Text und dergleichen sicher, dass der Mimetyp etwas wie Anwendung / Oktett-Stream ist
PHP-Code
quelle
Kurz gesagt, es gibt keinen einfacheren Weg. Sie müssen eine weitere Serveranforderung stellen, um die PDF-Datei anzuzeigen. Es gibt zwar nur wenige Alternativen, diese sind jedoch nicht perfekt und funktionieren nicht in allen Browsern:
quelle
Content-Disposition: attachment;filename="file.txt"
) gelöst , aber ich möchte diesen Ansatz beim nächsten Mal unbedingt ausprobieren. Ich hatte zuvorURI
Daten für Miniaturansichten verwendet, aber es kam mir nie in den Sinn, sie für Downloads zu verwenden - danke, dass Sie dieses Nugget geteilt haben.Es ist schon eine Weile her, dass diese Frage gestellt wurde, aber ich hatte die gleiche Herausforderung und möchte meine Lösung teilen. Es werden Elemente aus den anderen Antworten verwendet, aber ich konnte es nicht vollständig finden. Es wird weder ein Formular noch ein Iframe verwendet, es ist jedoch ein Post / Get-Anforderungspaar erforderlich. Anstatt die Datei zwischen den Anforderungen zu speichern, werden die Post-Daten gespeichert. Es scheint sowohl einfach als auch effektiv zu sein.
Klient
Server
quelle
quelle
Nicht nur eine Antwort auf den ursprünglichen Beitrag, sondern eine schnelle und schmutzige Lösung, um ein JSON-Objekt auf dem Server zu veröffentlichen und dynamisch einen Download zu generieren.
Clientseitige jQuery:
..und dann die JSON-Zeichenfolge auf der Serverseite dekodieren und Header zum Herunterladen festlegen (PHP-Beispiel):
quelle
Ich denke, der beste Ansatz ist die Verwendung einer Kombination. Ihr zweiter Ansatz scheint eine elegante Lösung zu sein, wenn Browser beteiligt sind.
Also je nachdem, wie der Anruf getätigt wird. (ob es sich um einen Browser oder einen Webdienstaufruf handelt) Sie können eine Kombination aus beiden verwenden, indem Sie eine URL an den Browser senden und Rohdaten an einen anderen Webdienstclient senden.
quelle
Ich bin jetzt seit zwei Tagen wach und versuche herauszufinden, wie ich eine Datei mit jquery mit Ajax-Aufruf herunterladen kann. All die Unterstützung, die ich bekam, konnte meiner Situation nicht helfen, bis ich es versuchte.
Client-Seite
Serverseite
Viel Glück.
quelle
Ich habe es vor langer Zeit irgendwo gefunden und es funktioniert perfekt!
quelle
Ein anderer Ansatz, anstatt die Datei auf dem Server zu speichern und abzurufen, besteht darin, .NET 4.0+ ObjectCache mit einem kurzen Ablauf bis zur zweiten Aktion zu verwenden (zu diesem Zeitpunkt kann sie endgültig gesichert werden). Der Grund, warum ich JQuery Ajax verwenden möchte, um den Aufruf auszuführen, ist, dass er asynchron ist. Das Erstellen meiner dynamischen PDF-Datei nimmt einige Zeit in Anspruch, und während dieser Zeit wird ein belebter Drehfelddialog angezeigt (es können auch andere Arbeiten ausgeführt werden). Der Ansatz, die im "Erfolg:" zurückgegebenen Daten zum Erstellen eines Blobs zu verwenden, funktioniert nicht zuverlässig. Dies hängt vom Inhalt der PDF-Datei ab. Es kann leicht durch Daten in der Antwort beschädigt werden, wenn es nicht vollständig textuell ist, was alles ist, was Ajax verarbeiten kann.
quelle
Lösung
Content-Disposition-Anhang scheint für mich zu funktionieren:
Problemumgehung
Anwendung / Oktett-Stream
Bei einem JSON passierte mir etwas Ähnliches. Auf der Serverseite setzte ich den Header auf self.set_header ("Content-Type", " application / json "), als ich ihn jedoch änderte in:
Es wurde automatisch heruntergeladen.
Beachten Sie auch, dass die Datei weiterhin das Suffix .json enthält, das Sie im Dateinamen-Header benötigen:
quelle
Mit HTML5 können Sie einfach einen Anker erstellen und darauf klicken. Es ist nicht erforderlich, es als untergeordnetes Dokument zum Dokument hinzuzufügen.
Alles erledigt.
Wenn Sie einen speziellen Namen für den Download haben möchten, übergeben Sie ihn einfach im
download
Attribut:quelle