我知道jQuery的ajax方法无法处理下载,我不想添加jQuery插件来执行此操作。
我想知道如何使用XMLHttpRequest发送POST数据来下载文件。
以下是我尝试的内容:
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执行此操作的正确示例。我不想创建一个带有POST操作的正确html表单,因为表单数据相当大,并且是动态创建的。
上述代码有问题吗?我错过了什么?我只是不知道如何将数据实际发送到客户端作为下载。
答案 0 :(得分:21)
如果在发送请求之前将XMLHttpRequest.responseType
属性设置为'blob'
,那么当您收到响应时,它将表示为blob。然后,您可以将blob保存到临时文件并导航到该文件。
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);
这是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.dispatchEvent(new MouseEvent('click'));
}
答案 1 :(得分:11)
XHR请求不会触发文件下载。我无法找到明确的要求,但W3C doc on XMLHttpRequest并未描述对内容处置=附件回复的任何特殊反应
如果不是POST请求,您可以通过window.open()在单独的选项卡中下载文件。 Here建议使用带有target = _blank
的隐藏表单UPD :自Blob API引入以来,此答案不再准确。有关详细信息,请参阅史蒂文的答案。
答案 2 :(得分:0)
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);
},
试试看,它对我有用。