我知道jQuery的ajax方法不能处理下载,我不想添加一个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做到这一点的适当示例。我不想用POST动作创建一个适当的html表单,因为表单数据相当大,并且是动态创建的。
上面的代码有问题吗?我错过了什么?我只是不知道如何将数据作为下载发送到客户端。
如果您在发送请求之前将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 (e) {
var blob = e.currentTarget.response;
var contentDispo = e.currentTarget.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 () { });
}
如果你不关心是否让浏览器导航到文件,当它是一个可见的文件类型,那么创建一个总是直接保存到file的方法要简单得多:
function saveBlob(blob, fileName) {
var a = document.createElement('a');
a.href = window.URL.createObjectURL(blob);
a.download = fileName;
a.dispatchEvent(new MouseEvent('click'));
}
UPDATE:自Blob API引入以来,这个答案不再准确。详情请参考Steven的回答。
原始答:
XHR请求不会触发文件下载。我找不到明确的要求,但是XMLHttpRequest上的W3C文档也没有描述对content-disposition=attachment响应的任何特殊反应
如果不是POST请求,可以在单独的选项卡中通过window.open()
下载文件。这里建议使用target=_blank
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);
},
对于我来说,它与fetch API一起工作。我无法使它在React/Typescript项目中使用XMLHttpRequest。也许是我不够努力。不管怎样,问题解决了。下面是代码:
const handleDownload = () => {
const url = `${config.API_ROOT}/download_route/${entityId}`;
const headers = new Headers();
headers.append('Authorization', `Token ${token}`);
fetch(url, { headers })
.then((response) => response.blob())
.then((blob) => {
// Create blob URL
const blobUrl = window.URL.createObjectURL(blob);
// Create a temporary anchor el
const anchorEl = document.createElement('a');
anchorEl.href = blobUrl;
anchorEl.download = `case_${entityId}_history.pdf`; // Set any filename and extension
anchorEl.style.display = 'none';
// Append the a tag to the DOM and click it to trigger download
document.body.appendChild(anchorEl);
anchorEl.click();
// Clean up
document.body.removeChild(anchorEl);
window.URL.revokeObjectURL(blobUrl);
})
.catch((error) => {
console.error('Error downloading file:', error);
});
};