小白我最近在准备一个关于Node中间层的分享,想要实现通过在Node层将json数据转化为xls文件,在浏览器直接下载该文件的功能。在实现这个功能的过程中,小白我踩了一些关于文件下载的坑,也学习到了一些东西,总结了这篇文章来和大家分享一下。
对于原来不懂文件下载的我,以为还是用ajax发送请求,浏览器就会自动下载,于是
let xhr = new XMLHttpRequest();
xhr.responseType = 'arraybuffer';
xhr.open('get', '/get/data/', true);
xhr.send();
xhr.onload = function() {
if(this.status === 200) {
console.log(this.response); // 二进制文件
}
}
复制代码
通过这段代码,可以获得文件的二进制流,但是为什么浏览器没有自动弹出文件下载呢?我如何把这个文件保存到我本地呢?
想要实现在客户端下载数据,因为浏览器安全策略的限制,直接使用ajax请求是无法实现的。但是我们可以使用一下几种方法来实现。
表单提交
使用表单提交的方式向后端发送请求,后端返回文件流到页面,就会触发浏览器自己的保存下载文件机制。
由于form表单提交有默认行为,会刷新到action的页面,但是我们只想实现在本页面下载文件。为了阻止页面跳转,就设置一个隐藏的iframe页面,将form的target属性指向这个iframe(target 属性规定在何处打开 action URL),这样就可以阻止页面跳转了。
downloadFile = (url) => {
let iframe = document.createElement('iframe');
iframe.style.display = 'none';
iframe.setAttribute('name', 'export');
document.body.appendChild(iframe);
let form = document.createElement('form');
form.setAttribute('target', 'export');
form.setAttribute('action', url);
iframe.appendChild(form);
document.body.appendChild(iframe);
form.submit();
iframe.onload = function() {
setTimeout(() => {
document.body.removeChild(iframe);
}, 1000);
};
}
downloadFile('/get/data/');
复制代码
Blob对象
使用JS中的Blob对象,也可以解决这个问题。Blob对象是一个类文件对象,我们可以使用它来存放我们接收到的二进制文件流。之后再使用URL对象指定文件的下载链接。得到文件的下载链接,你就可以选择使用原生的window.open或者h5中a标签新增的download属相来下载文件了。
let data; // 存储使用ajax请求到的二进制数据
let blob = new Blob(data, {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
let objectURL = window.URL.createObjectURL(blob);
window.open(objectURL);
let a = document.createElement('a');
a.setAttribute('href', objectURL);
a.setAttribute('download', fileName);
复制代码
注: 使用这个方法,需要考虑download的兼容性问题。对于较大文件的下载,是否存在问题还需要考量。
对于文件的下载,其实还有很多其他的方法,比如说download或者FileSaver.js等已经成熟的库。具体选择哪种方式就看你使用的场景和需求了。