webentwicklung-frage-antwort-db.com.de

Prompt-Dateidownload mit XMLHttpRequest

Ich bin mir bewusst, dass die Ajax-Methode von jQuery keine Downloads verarbeiten kann, und ich möchte dazu kein jQuery-Plugin hinzufügen.

Ich möchte wissen, wie man POST -Daten mit XMLHttpRequest sendet, um eine Datei herunterzuladen.

Folgendes habe ich ausprobiert:

var postData = new FormData();
postData.append('cells', JSON.stringify(output));

var xhr = new XMLHttpRequest();
xhr.open('POST', '/export/', true);
xhr.setRequestHeader("X-CSRFToken", csrftoken);
xhr.responseType = 'arraybuffer';
xhr.onload = function (e) {
    console.log(e);
    console.log(xhr);
}
xhr.send(postData);

Ich arbeite mit Django und die Datei scheint erfolgreich an den Client zurückzusenden. Auf der Registerkarte "Netzwerk" in Chrome kann ich auf der Registerkarte "Vorschau" Kauderwelsch sehen (was ich erwarte). Ich möchte jedoch eine Zip-Datei zurückschicken, keine Textdarstellung der Zip-Datei. Hier ist das Django-Backend:

wrapper = FileWrapper(tmp_file)
response = HttpResponse(wrapper, content_type='application/Zip')
response['Content-Disposition'] = "attachment; filename=export.Zip"
response['Content-Length'] = tmp_file.tell()
return response

Ich habe das jetzt stundenlang gesucht, ohne ein richtiges Beispiel dafür zu finden, wie dies mit XMLHttpRequests geschieht. Ich möchte kein richtiges HTML-Formular mit der Aktion POST erstellen, da die Formulardaten ziemlich groß und dynamisch erstellt werden.

Stimmt etwas mit dem obigen Code nicht? Was fehlt mir? Ich weiß einfach nicht, wie ich die Daten tatsächlich als Download an den Client senden soll.

12
bozdoz

Die XHR-Anforderung löst keinen Dateidownload aus. Ich kann keine explizite Anforderung finden, aber W3C doc in XMLHttpRequest beschreibt keine besondere Reaktion auf content-disposition = Attachment-Antworten

Sie können die Datei mit window.open () auf einer separaten Registerkarte herunterladen, wenn dies nicht die Anforderung POST war. Hier Es wurde vorgeschlagen, versteckte Form mit target = _blank zu verwenden

UPD: Diese Antwort ist seit der Einführung von Blob API nicht mehr korrekt. Einzelheiten entnehmen Sie bitte der Antwort von Steven.

10
Marat

Wenn Sie die XMLHttpRequest.responseType -Eigenschaft vor dem Senden der Anfrage auf 'blob' setzen, wird die Antwort als Antwort zurückgesendet und als Blob dargestellt. Sie können den Blob dann in einer temporären Datei speichern und zu ihm navigieren.

var postData = new FormData();
postData.append('cells', JSON.stringify(output));

var xhr = new XMLHttpRequest();
xhr.open('POST', '/export/', true);
xhr.setRequestHeader('X-CSRFToken', csrftoken);
xhr.responseType = 'blob';
xhr.onload = function (this, event) {
    var blob = this.response;
    var contentDispo = this.getResponseHeader('Content-Disposition');
    // https://stackoverflow.com/a/23054920/
    var fileName = contentDispo.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)[1];
    saveOrOpenBlob(blob, fileName);
}
xhr.send(postData);

Und hier ist eine Beispielimplementierung von saveOrOpenBlob:

function saveOrOpenBlob(blob, fileName) {
    window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
    window.requestFileSystem(window.TEMPORARY, 1024 * 1024, function (fs) {
        fs.root.getFile(fileName, { create: true }, function (fileEntry) {
            fileEntry.createWriter(function (fileWriter) {
                fileWriter.addEventListener("writeend", function () {
                    window.location = fileEntry.toURL();
                }, false);
                fileWriter.write(blob, "_blank");
            }, function () { });
        }, function () { });
    }, function () { });
}

Wenn Sie nicht darauf achten, dass der Browser bei einem sichtbaren Dateityp zu der Datei navigiert, ist es wesentlich einfacher, eine Methode zu erstellen, die immer direkt in einer Datei gespeichert wird:

function saveBlob(blob, fileName) {
    var a = document.createElement('a');
    a.href = window.URL.createObjectURL(blob);
    a.download = fileName;
    a.dispatchEvent(new MouseEvent('click'));
}
18
Steven Doggart

download: function(){
    var postData = new FormData();
		var xhr = new XMLHttpRequest();
		xhr.open('GET', downloadUrl, true);
		xhr.responseType = 'blob';
		xhr.onload = function (e) {
			var blob = xhr.response;
			this.saveOrOpenBlob(blob);
		}.bind(this)
		xhr.send(postData);
 }

saveOrOpenBlob: function(blob) {
		var assetRecord = this.getAssetRecord();
		var fileName = 'Test.mp4'
		var tempEl = document.createElement("a");
    	document.body.appendChild(tempEl);
    	tempEl.style = "display: none";
        url = window.URL.createObjectURL(blob);
        tempEl.href = url;
        tempEl.download = fileName;
        tempEl.click();
		window.URL.revokeObjectURL(url);
	},

Versuchen Sie dies, es funktioniert für mich.

0
Kamlesh Kumar