浏览器文件下载

3,289 阅读2分钟

小白我最近在准备一个关于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等已经成熟的库。具体选择哪种方式就看你使用的场景和需求了。