Запрос загрузки файла с помощью XMLHttpRequest
Я знаю, что метод ajax jQuery не может обрабатывать загрузки, и я не хочу добавлять плагин jQuery для этого.
Я хочу знать, как отправлять данные POST с помощью XMLHttpRequest для загрузки файла.
вот что я пробовал:
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);
Я работаю с Django, и файл будет успешно отправляет обратно клиенту. На вкладке "Сеть" в Chrome я вижу тарабарщину на вкладке предварительного просмотра (что я ожидаю). Но я хочу отправить назад zip-файл, а не текстовое представление файла zip. Вот задняя часть Django:
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
Я искал это в течение нескольких часов, не найдя надлежащего примера о том, как это сделать с XMLHttpRequests. Я не хочу создавать правильную html-форму с действием POST, потому что данные формы довольно большие и динамически создаются.
что-то не так С выше код? Я что-то упускаю? Я просто не знаю, как на самом деле отправить данные клиенту в виде скачать.
2 ответов
запрос XHR не вызовет загрузку файла. Я не могу найти явное требование, но W3C doc на XMLHttpRequest не описывает никакой специальной реакции на content-disposition=attachment responses либо
вы можете скачать файл по окну.откройте () на отдельной вкладке, если это не был запрос POST. здесь было предложено использовать скрытую форму с target=_blank
UPD: этот ответ больше не является точным, так как введение Blob API. Подробности см. В ответе Стивена.
если вы выберите XMLHttpRequest.responseType
свойство 'blob'
перед отправкой запроса, а затем, когда вы получите ответ обратно, он будет представлен как blob. Затем вы можете сохранить blob во временный файл и перейти к нему.
ar 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 (e) {
var blob = xhr.response;
var fileName = xhr.getResponseHeader("Content-Disposition").match(/\sfilename="([^"]+)"(\s|$)/)[1];
saveOrOpenBlob(blob, fileName);
}
xhr.send(postData);
и вот пример реализации 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 () { });
}
если вы не заботитесь о том, чтобы браузер переходил к файлу, когда это видимый тип файла, то сделать метод, который всегда сохраняет непосредственно в файл, очень проще:
function saveBlob(blob, fileName) {
var a = document.createElement("a");
a.href = window.URL.createObjectURL(blob);
a.download = fileName;
a.click();
}