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?

24voto

ndpu Punkte 20976

Ich habe eine kleine Funktion als Workaround-Lösung erstellt (inspiriert von @JohnCulviner Plugin):

// creates iframe and form in it with hidden field,
// then submit form with provided data
// url - form url
// data - data to form field
// input_name - form hidden input name

function ajax_download(url, data, input_name) {
    var $iframe,
        iframe_doc,
        iframe_html;

    if (($iframe = $('#download_iframe')).length === 0) {
        $iframe = $("<iframe id='download_iframe'" +
                    " style='display: none' src='about:blank'></iframe>"
                   ).appendTo("body");
    }

    iframe_doc = $iframe[0].contentWindow || $iframe[0].contentDocument;
    if (iframe_doc.document) {
        iframe_doc = iframe_doc.document;
    }

    iframe_html = "<html><head></head><body><form method='POST' action='" +
                  url +"'>" +
                  "<input type=hidden name='" + input_name + "' value='" +
                  JSON.stringify(data) +"'/></form>" +
                  "</body></html>";

    iframe_doc.open();
    iframe_doc.write(iframe_html);
    $(iframe_doc).find('form').submit();
}

Demo mit Klick-Ereignis:

$('#someid').on('click', function() {
    ajax_download('/download.action', {'para1': 1, 'para2': 2}, 'dataname');
});

17voto

Naren Yellavula Punkte 6408

Ich hatte das gleiche Problem und habe es erfolgreich gelöst. Mein Anwendungsfall ist dieser.

" Senden Sie JSON-Daten an den Server und erhalten Sie eine Exceldatei. Diese Exceldatei wird vom Server erstellt und als Antwort an den Client zurückgegeben. Herunterladen dieser Antwort als Datei mit benutzerdefiniertem Namen im Browser "

$("#my-button").on("click", function(){

// Data to post
data = {
    ids: [1, 2, 3, 4, 5]
};

// Use XMLHttpRequest instead of Jquery $ajax
xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
    var a;
    if (xhttp.readyState === 4 && xhttp.status === 200) {
        // Trick for making downloadable link
        a = document.createElement('a');
        a.href = window.URL.createObjectURL(xhttp.response);
        // Give filename you wish to download
        a.download = "test-file.xls";
        a.style.display = 'none';
        document.body.appendChild(a);
        a.click();
    }
};
// Post data to URL which handles post request
xhttp.open("POST", excelDownloadUrl);
xhttp.setRequestHeader("Content-Type", "application/json");
// You should set responseType as blob for binary responses
xhttp.responseType = 'blob';
xhttp.send(JSON.stringify(data));
});

Das obige Snippet macht gerade folgendes

  • Senden eines Arrays als JSON an den Server mit XMLHttpRequest.
  • Nach dem Abrufen von Inhalten als Blob (binär), erstellen wir eine herunterladbare URL und fügen Sie es auf unsichtbare "a" Link dann klicken Sie darauf. Ich habe hier eine POST-Anfrage gestellt. Stattdessen können Sie auch einen einfachen GET verwenden. Wir können die Datei nicht über Ajax herunterladen, sondern müssen XMLHttpRequest verwenden.

Hier müssen wir einige Dinge auf der Serverseite sorgfältig einstellen. Ich setze einige Header in Python Django HttpResponse. Sie müssen sie entsprechend einstellen, wenn Sie andere Programmiersprachen verwenden.

# In python django code
response = HttpResponse(file_content, content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")

Da ich hier xls (excel) herunterlade, habe ich contentType auf oben eingestellt. Sie müssen ihn entsprechend Ihrem Dateityp einstellen. Sie können diese Technik verwenden, um jede Art von Dateien herunterzuladen.

15voto

Shayne Punkte 1586

Ok, basierend auf ndpu's Code hier ist eine verbesserte (ich denke) Version von ajax_download;-

function ajax_download(url, data) {
    var $iframe,
        iframe_doc,
        iframe_html;

    if (($iframe = $('#download_iframe')).length === 0) {
        $iframe = $("<iframe id='download_iframe'" +
                    " style='display: none' src='about:blank'></iframe>"
                   ).appendTo("body");
    }

    iframe_doc = $iframe[0].contentWindow || $iframe[0].contentDocument;
    if (iframe_doc.document) {
        iframe_doc = iframe_doc.document;
    }

    iframe_html = "<html><head></head><body><form method='POST' action='" +
                  url +"'>" 

    Object.keys(data).forEach(function(key){
        iframe_html += "<input type='hidden' name='"+key+"' value='"+data[key]+"'>";

    });

        iframe_html +="</form></body></html>";

    iframe_doc.open();
    iframe_doc.write(iframe_html);
    $(iframe_doc).find('form').submit();
}

Verwenden Sie dies so;-

$('#someid').on('click', function() {
    ajax_download('/download.action', {'para1': 1, 'para2': 2});
});

Die Parameter werden als richtige Post-Parameter gesendet, als ob sie von einer Eingabe kämen, und nicht als json-kodierter String wie im vorherigen Beispiel.

CAVEAT: Seien Sie vorsichtig mit der Möglichkeit einer variablen Injektion auf diesen Formularen. Es könnte einen sichereren Weg geben, diese Variablen zu kodieren. Alternativ können Sie auch das Escapen in Erwägung ziehen.

14voto

M46 Punkte 777

Mein Ansatz basiert vollständig auf jQuery. Das Problem für mich war, dass es ein POST-HTTP-Aufruf sein muss. Und ich wollte, dass es durch jQuery allein getan werden.

Die Lösung:

$.ajax({
    type: "POST",
    url: "/some/webpage",
    headers: {'X-CSRF-TOKEN': csrfToken},
    data: additionalDataToSend,
    dataType: "text",
    success: function(result) {
        let blob = new Blob([result], { type: "application/octetstream" }); 

        let a = document.createElement('a');
        a.href = window.URL.createObjectURL(blob);
        a.download = "test.xml";;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        window.URL.revokeObjectURL(a.href);

        ...
    },
    error: errorDialog
});

Erläuterung:

Was ich und viele andere tun, ist, einen Link auf der Webseite zu erstellen, der angibt, dass das Ziel heruntergeladen werden soll, und das Ergebnis der http-Anfrage als Ziel anzugeben. Danach füge ich den Link an das Dokument an, als einfach Klicken Sie auf die Verknüpfung und das anschließende Entfernen der Verknüpfung. Sie brauchen keinen iframe mehr.

Der Zauber liegt in den Linien

let blob = new Blob([result], { type: "application/octetstream" }); 
a.href = window.URL.createObjectURL(blob);

Der interessante Punkt ist, dass diese Lösung nur mit einem " Klecks ". Wie Sie in anderen Antworten sehen können, verwenden einige einfach einen Blob, ohne zu erklären, warum und wie man ihn erstellt. Wie Sie z.B. in der Dokumentation für Mozilla-Entwickler Sie benötigen eine Datei, Medienressource oder einen Blob für die Funktion " createObjectURL() " zu funktionieren. Das Problem ist, dass Ihre http-Antwort möglicherweise keines davon ist. Daher müssen Sie als erstes Ihre Antwort in einen Blob umwandeln. Dies geschieht in der ersten Zeile. Dann können Sie die " createObjectURL " mit Ihrem neu erstellten Blob. Wenn Sie dann auf den Link klicken, öffnet Ihr Browser ein Dialogfeld zum Speichern der Datei und Sie können Ihre Daten speichern. Natürlich ist es möglich, dass Sie keinen festen Dateinamen für Ihre herunterzuladende Datei angeben können. Dann müssen Sie Ihre Antwort komplexer gestalten wie in der Antwort von Lukas.

Und vergessen Sie nicht, den Speicher freizugeben, besonders wenn Sie mit großen Dateien arbeiten. Weitere Beispiele und Informationen finden Sie unter die Details des JS-Blob-Objekts

9voto

manukyanv07 Punkte 443

Hier ist, was ich getan habe, reines Javascript und HTML. Habe es nicht getestet, aber das sollte in allen Browsern funktionieren.

Javascript-Funktion

var iframe = document.createElement('iframe');
iframe.id = "IFRAMEID";
iframe.style.display = 'none';
document.body.appendChild(iframe);
iframe.src = 'SERVERURL'+'?' + $.param($scope.filtro);
iframe.addEventListener("load", function () {
     console.log("FILE LOAD DONE.. Download should start now");
});

Verwendung von Komponenten, die in allen Browsern unterstützt werden, ohne zusätzliche Bibliotheken.

enter image description here enter image description here

Hier ist mein serverseitiger JAVA Spring-Controller-Code.

@RequestMapping(value = "/rootto/my/xlsx", method = RequestMethod.GET)
public void downloadExcelFile(@RequestParam(value = "param1", required = false) String param1,
    HttpServletRequest request, HttpServletResponse response)
            throws ParseException {

    Workbook wb = service.getWorkbook(param1);
    if (wb != null) {
        try {
            String fileName = "myfile_" + sdf.format(new Date());
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-disposition", "attachment; filename=\"" + fileName + ".xlsx\"");
            wb.write(response.getOutputStream());
            response.getOutputStream().close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    }

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