在我们的开发过程中,文件下载是一个常见的功能。而目前的开发方式常采用前后端分离模式,所以文件下载时,前端可以发送ajax请求获取文件流,然后利用Blob对象生成文件后,再下载至本地。这种方式比转灵活,非常适合处理一些实时生成文件下载,当生成过程出现异常时,可以根据获取的类型,进行分类处理。

一、Blob对象

Blob对象 表示一个不可变、原始数据的类文件对象。Blob 表示的不一定是JavaScript原生格式的数据。File接口基于Blob,继承了blob的功能并将其扩展使其支持用户系统上的文件。

构造函数:

1
var blob = new Blob( array, options );

参数说明:

  • array 是一个由ArrayBuffer, ArrayBufferView, Blob, DOMString 等对象构成的 Array ,或者其他类似对象的混合体,它将会被放进 Blob。DOMStrings 会被编码为 UTF-8。
  • options 是一个可选的BlobPropertyBag字典,它可能会指定如下两个属性:
    type,默认值为 “”,它代表了将会被放入到 blob 中的数组内容的 MIME 类型。
    endings,默认值为”transparent”,用于指定包含行结束符\n的字符串如何被写入。 它是以下两个值中的一个: “native”,代表行结束符会被更改为适合宿主操作系统文件系统的换行符,或者 “transparent”,代表会保持 blob 中保存的结束符不变 Non-Standard

二、URL对象

URL 接口用于解析,构造,规范化和编码 URLs。 它通过提供允许您轻松阅读和修改 URL 组件的属性来工作。 通常,通过在调用 URL 的构造函数时将 URL 指定为字符串或提供相对 URL 和基本 URL 来创建新的 URL 对象。 然后,您可以轻松读取 URL 的已解析组成部分或对 URL 进行更改。

静态方法:

  • URL.createObjectURL();

URL.createObjectURL() 静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的 URL。这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的 URL 对象表示指定的 File 对象或 Blob 对象。

  • URL.revokeObjectURL()

URL.revokeObjectURL() 静态方法用来释放一个之前已经存在的、通过调用 URL.createObjectURL() 创建的 URL 对象。当你结束使用某个 URL 对象之后,应该通过调用这个方法来让浏览器知道不用在内存中继续保留对这个文件的引用了。

特别说明:

在每次调用 createObjectURL() 方法时,都会创建一个新的 URL 对象,即使你已经用相同的对象作为参数创建过。当不再需要这些 URL 对象时,每个对象必须通过调用 URL.revokeObjectURL() 方法来释放。
浏览器在 document 卸载的时候,会自动释放它们,但是为了获得最佳性能和内存使用状况,你应该在安全的时机主动释放掉它们。

三、利用a标签下载

  • 生成a标签

    1
    const link = document.createElement('a');
  • href属性指定下载链接

    1
    link.href = window.URL.createObjectURL(blob);
  • download属性指定文件名
    只有 Firefox 和 Chrome 支持 download 属性。若在html文档中使用时,当URL存在跨域时,会导致download属性指定的文件名无效

    1
    link.download = fileName;
  • click()事件触发下载

    1
    link.click();

四、兼容IE

1
window.navigator.msSaveOrOpenBlob(blob, fileName);

五、完整代码

基于axios请求库,及采用Promise写法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
let fileName = "abc.xlsx";
let downloadUrl = "http://xxx.xxx.com";

axios.get(`downloadUrl`, {
responseType: 'blob',
}).then(res => {
if (res.status == 200) {
// 接口异常时返回 Json 数据
if (res.type == "application/json") {
let reader = new FileReader();
// message 为消息字段名
let data = JSON.parse(e.target.result);
reader.onload = e => alert(data.message);
reader.readAsText(res);
} else {
let blob = new Blob([res.data], {
type: res.type
});
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
// for IE
window.navigator.msSaveOrOpenBlob(blob, fileName);
} else {
// for Non-IE
let objectUrl = URL.createObjectURL(blob);
let link = document.createElement("a");
link.href = objectUrl;
link.setAttribute("download", fileName);
document.body.appendChild(link);
link.click();
window.URL.revokeObjectURL(link.href);
}
}
} else {
// error handler
alert("请求下载数据异常");
}
});