501 Stimmen

Herunterladen einer Datei mit jQuery.Ajax

Ich habe eine Struts2-Aktion auf der Serverseite zum Herunterladen von Dateien.

<action name="download" class="com.xxx.DownAction">
    <result name="success" type="stream">
        <param name="contentType">text/plain</param>
        <param name="inputName">imageStream</param>
        <param name="contentDisposition">attachment;filename={fileName}</param>
        <param name="bufferSize">1024</param>
    </result>
</action>

Wenn ich jedoch die Aktion mit dem jQuery:

$.post(
  "/download.action",{
    para1:value1,
    para2:value2
    ....
  },function(data){
      console.info(data);
   }
);

in Firebug sehe ich, dass die Daten mit der Binärer Strom . Ich frage mich, wie man die Fenster zum Herunterladen von Dateien mit der der Benutzer die Datei lokal speichern kann?

772voto

John Culviner Punkte 20761

Update 2019 für moderne Browser

Dies ist der Ansatz, den ich jetzt empfehlen würde, allerdings mit einigen Vorbehalten:

  • Ein relativ moderner Browser ist erforderlich
  • Wenn die Datei erwartet wird, dass sie sehr groß sollten Sie wahrscheinlich etwas Ähnliches wie den ursprünglichen Ansatz (iframe und Cookie) tun, weil einige der unten genannten Operationen wahrscheinlich Systemspeicher verbrauchen könnten, der mindestens so groß ist wie die heruntergeladene Datei und/oder andere interessante CPU-Nebeneffekte.

    fetch('https://jsonplaceholder.typicode.com/todos/1') .then(resp => resp.blob()) .then(blob => { const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.style.display = 'none'; a.href = url; // the filename you want a.download = 'todo-1.json'; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); alert('your file has downloaded!'); // or you know, something with better UX... }) .catch(() => alert('oh no!'));

2012 Ursprünglicher jQuery/iframe/Cookie-basierter Ansatz

Bläulich ist völlig richtig, man kann es nicht über Ajax machen, weil JavaScript keine Dateien direkt auf dem Computer eines Benutzers speichern kann (aus Sicherheitsgründen). U des Hauptfensters URL bei Ihrem Dateidownload bedeutet, dass Sie nur wenig Kontrolle darüber haben, was der Benutzer beim Herunterladen einer Datei erlebt.

Ich habe jQuery Datei Download die eine "Ajax-ähnliche" Erfahrung mit Dateidownloads ermöglicht, komplett mit OnSuccess- und OnFailure-Callbacks, um eine bessere Benutzererfahrung zu bieten. Werfen Sie einen Blick auf meine Blog-Beitrag über das allgemeine Problem, das das Plugin löst, und einige Möglichkeiten, es zu nutzen, sowie eine Demo von jQuery File Download in Aktion . Hier ist die Quelle

Hier ist ein einfaches Anwendungsbeispiel für das Plugin Quelle mit Versprechungen. Die Demo-Seite enthält auch viele andere Beispiele für "bessere UX".

$.fileDownload('some/file.pdf')
    .done(function () { alert('File download a success!'); })
    .fail(function () { alert('File download failed!'); });

Je nachdem, welche Browser Sie unterstützen müssen, können Sie Folgendes verwenden https://github.com/eligrey/FileSaver.js/ die eine deutlichere Kontrolle ermöglicht als die IFRAME-Methode, die jQuery File Download verwendet.

260voto

bluish Punkte 24479

_Niemand hat dies gepostet @Pekka's Lösung ... also werde ich es posten. Es kann jemandem helfen._

Sie müssen dies nicht über Ajax tun. Verwenden Sie einfach

window.location="download.action?para1=value1...."

47voto

Luke Madhanga Punkte 5287

Sie können mit HTML5

NB: Die zurückgegebenen Dateidaten MÜSSEN base64-kodiert sein, da man Binärdaten nicht JSON-kodieren kann.

In meinem AJAX Antwort Ich habe eine Datenstruktur, die wie folgt aussieht:

{
    result: 'OK',
    download: {
        mimetype: string(mimetype in the form 'major/minor'),
        filename: string(the name of the file to download),
        data: base64(the binary data as base64 to download)
    }
}

Das bedeutet, dass ich Folgendes tun kann, um eine Datei über AJAX zu speichern

var a = document.createElement('a');
if (window.URL && window.Blob && ('download' in a) && window.atob) {
    // Do it the HTML5 compliant way
    var blob = base64ToBlob(result.download.data, result.download.mimetype);
    var url = window.URL.createObjectURL(blob);
    a.href = url;
    a.download = result.download.filename;
    a.click();
    window.URL.revokeObjectURL(url);
}

Die Funktion base64ToBlob stammt aus aquí und muss in Übereinstimmung mit dieser Funktion verwendet werden

function base64ToBlob(base64, mimetype, slicesize) {
    if (!window.atob || !window.Uint8Array) {
        // The current browser doesn't have the atob function. Cannot continue
        return null;
    }
    mimetype = mimetype || '';
    slicesize = slicesize || 512;
    var bytechars = atob(base64);
    var bytearrays = [];
    for (var offset = 0; offset < bytechars.length; offset += slicesize) {
        var slice = bytechars.slice(offset, offset + slicesize);
        var bytenums = new Array(slice.length);
        for (var i = 0; i < slice.length; i++) {
            bytenums[i] = slice.charCodeAt(i);
        }
        var bytearray = new Uint8Array(bytenums);
        bytearrays[bytearrays.length] = bytearray;
    }
    return new Blob(bytearrays, {type: mimetype});
};

Das ist gut, wenn Ihr Server Dateidaten ausgibt, die gespeichert werden sollen. Ich habe jedoch noch nicht ganz herausgefunden, wie man einen HTML4-Fallback implementieren könnte

45voto

João Marcos Punkte 3783

Der einfache Weg, um den Browser dazu zu bringen, eine Datei herunterzuladen, besteht darin, die Anfrage so zu stellen:

 function downloadFile(urlToSend) {
     var req = new XMLHttpRequest();
     req.open("GET", urlToSend, true);
     req.responseType = "blob";
     req.onload = function (event) {
         var blob = req.response;
         var fileName = req.getResponseHeader("fileName") //if you have the fileName header available
         var link=document.createElement('a');
         link.href=window.URL.createObjectURL(blob);
         link.download=fileName;
         link.click();
     };

     req.send();
 }

Dadurch wird das Download-Popup-Fenster des Browsers geöffnet.

27voto

Andrea Ligios Punkte 47882

1. Framework-unabhängig: Servlet lädt Datei als Anhang herunter

<!-- with JS -->
<a href="javascript:window.location='downloadServlet?param1=value1'">
    download
</a>

<!-- without JS -->
<a href="downloadServlet?param1=value1" >download</a>

2. Struts2-Framework: Aktion zum Herunterladen der Datei als Anhang

<!-- with JS -->
<a href="javascript:window.location='downloadAction.action?param1=value1'">
    download
</a>

<!-- without JS -->
<a href="downloadAction.action?param1=value1" >download</a>

Es wäre besser, die <s:a> Markierung mit OGNL zu einer URL erstellt mit <s:url> Tag:

<!-- without JS, with Struts tags: THE RIGHT WAY -->    
<s:url action="downloadAction.action" var="url">
    <s:param name="param1">value1</s:param>
</s:ulr>
<s:a href="%{url}" >download</s:a>

In den oben genannten Fällen müssen Sie brauchen zum Schreiben der Inhalt-Disposition Kopfzeile zum Antwort mit der Angabe, dass die Datei heruntergeladen werden muss ( attachment ) und nicht durch den Browser geöffnet ( inline ). Sie brauchen zur Angabe der Inhalt Typ und fügen Sie den Dateinamen und die Länge hinzu (damit der Browser einen realistischen Fortschrittsbalken zeichnen kann).

Zum Beispiel beim Herunterladen einer ZIP-Datei:

response.setContentType("application/zip");
response.addHeader("Content-Disposition", 
                   "attachment; filename=\"name of my file.zip\"");
response.setHeader("Content-Length", myFile.length()); // or myByte[].length...

Mit Struts2 (es sei denn, Sie verwenden die Action als Servlet, ein Hack für direktes Streaming zum Beispiel), müssen Sie nicht direkt etwas in die Antwort schreiben; es genügt, wenn Sie die Stream-Ergebnis-Typ und die Konfiguration in struts.xml wird funktionieren: BEISPIEL

<result name="success" type="stream">
   <param name="contentType">application/zip</param>
   <param name="contentDisposition">attachment;filename="${fileName}"</param>
   <param name="contentLength">${fileLength}</param>
</result>

3. Framework-unabhängig (/ Struts2 Framework): Servlet(/Action) öffnet Datei innerhalb des Browsers

Wenn Sie die Datei im Browser öffnen möchten, anstatt sie herunterzuladen, können Sie die Inhalt-Disposition muss eingestellt werden auf Inline , aber das Ziel kann nicht die aktuelle Fensterposition sein; Sie müssen ein neues Fenster anvisieren, das von javascript erstellt wird, ein <iframe> auf der Seite oder ein neues Fenster, das mit der Option "diskutiert" target="_blank" erstellt wird:

<!-- From a parent page into an IFrame without javascript -->   
<a href="downloadServlet?param1=value1" target="iFrameName">
    download
</a>

<!-- In a new window without javascript --> 
<a href="downloadServlet?param1=value1" target="_blank">
    download
</a>

<!-- In a new window with javascript -->    
<a href="javascript:window.open('downloadServlet?param1=value1');" >
    download
</a>

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X