2014-03-28 137 views
8

我知道jQuery的ajax方法无法处理下载,我不想添加jQuery插件来执行此操作。用XMLHttpRequest下载提示文件

我想知道如何使用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 

我搜索好几个小时了,现在没有找到如何与XMLHttpRequest的做一个适当的例子。我不想使用POST操作创建合适的HTML表单,因为表单数据相当大,并且动态创建。

上面的代码有问题吗?我失踪的东西?我只是不知道如何将数据实际上作为下载发送到客户端。

+0

我在这里没有看到任何错误。如果您更改视图以响应GET请求返回文件并在浏览器中打开URL,它是否按预期下载文件? – Marat

+0

是的,它下载@Marat。我可以通过使用正常的html表单并使用'/ export /'来获取它,我从xhr得到响应,但它不会触发下载。 xhr可能无法下载到客户端吗? – bozdoz

回答

8

XHR请求不会触发文件下载。我找不到明确的要求,但W3C doc on XMLHttpRequest没有描述任何有关内容处置的特殊反应=附件响应

如果不是POST请求,您可以在单独的选项卡中通过window.open()下载文件。 Here有人建议使用隐藏的表单与目标= _blank

UPD:这个答案是不准确的,因为再引进Blob API。详情请参阅Steven的回答。

+0

不知道你是否真的需要window.open。我已经完成了我没有设定的目标=“_ blank”'。但我想这是正确的,XHR不会触发下载。 – bozdoz

11

如果在发送请求之前将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(); 
} 
+0

这节省了我的一天:)谢谢。 – Katti