文件下载
文件下载方式
前端涉及到的文件下载还是很多应用场景的,那么前端文件下载有多少种方式呢?每种方式有什么优缺点呢?下面就来一一介绍。
a标签
定义与用法
- 首先实现
download
功能,条件必须满足:所要下载的文件与js
或当前页面同源。即window.location.protocol
(传输协议)+window.location.host
(域名)必须有,且一致; - 如果是本地文件,请启动本地服务,使用
localhost
访问页面; - 通过
a
标签的download
属性来实现文件下载;download为h5中新增的a标签属性;download+href使a标签具备点击下载功能; download
属性也可以设置一个值来规定下载文件的名称;若没有设置拓展名,浏览器将自动检测正确的拓展名(.img,.png、.pdf);
兼容性测试及结果
- 代码
1 | <a href="./imgs/cs.jpg">同源图片,不带download</a> |
1 | function down(url) { |
- pc端浏览器兼容性
总结
- html不支持的文件,无论同源还是不同源,有没有download属性,都会下载。
- html支持的文件,同源且有download属性,除ie外都会下载。
- html支持的文件,不同源,无论有无download属性,都不会下载,浏览器会直接跳转打开。
Blob对象
场景:后端返回给前端
文件流
,前端通过Blob
下载;文件流格式如下:
Blob对象
下面是blob
对象的定义,来自MDN:
Blob
对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成ReadableStream
来用于数据操作。
Blob
表示的不一定是JavaScript
原生格式的数据。File
接口基于Blob
,继承了blob
的功能并将其扩展以支持用户系统上的文件。
blob
对象是html5
新增的对象,它的作用是用来存储二进制数据的,比如图片、视频、音频等,它的使用方法如下:
1 | /** |
这里主要关注的是type
属性,默认情况下,blob
对象是没有type
属性的,那么这个Blob
就是一个无类型的Blob
,文件不会损毁,但是无法被正常识别。
URL.createObjectURL
下面是blob
对象的定义,来自MDN:
URL.createObjectURL() 静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的 URL。这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的 URL 对象表示指定的 File 对象或 Blob 对象。
这个方法是用来创建一个url
的,它的作用是把一个blob
对象转换成一个url
,这个url
可以用来下载文件,也可以用来预览文件,代码如下:
1 | const url = URL.createObjectURL(blob) |
这里需要注意的是,这个url
的生命周期和创建它的窗口中的document
绑定,也就是说,当我们的document
被销毁后,这个url
就会失效,会自动释放它们,但是为了获得最佳性能和内存使用状况,我们应该在安全的时机主动释放掉它们,代码如下:
1 | URL.revokeObjectURL(url) |
下载文件流
指定返回数据格式
首先指定返回数据格式为blob:
responseType: 'blob'
1 | // 导出报表 |
响应头headers
获取文件信息
在响应数据
response.headers["content-disposition"]
中获取文件信息;包含文件名和文件类型;如下图所示:
可以在响应拦截器里面做数据处理:
- 中文转码了,转回去;
- 将文件信息存到缓存,调用下载接口的时候获取文件信息;(给a标签的download设置文件名)
1 | //接收到响应数据并成功后的一些共有的处理 |
调用下载接口
- 我们可以打印一下res,是一个Blob对象;(如果接口没有设置responseType: ‘blob’,这里是后端返回的文件流)
1 | getMeetRoomExport(this.exportParams).then((res) => { |
- 接口请求
这里和后端商量是
docx
类型的文件,所以type
值如下所示,其他类型的type
值设置可参考MDN;
1 | getMeetRoomExport(this.exportParams).then((res) => { |
至此,文件就会下载成功;
下载拓展
回到我们刚才下载的问题,我们是通过
blob
对象来解决,但是我们的type
属性是写死的,如果在文件类型是确定的情况下是没问题的,但是如果这个接口就是下载文件的接口,文件可能是各种类型的,我们应该怎么处理?
- 和接口提供者进行协商,确定下载的文件的格式,然后前端将
type
写死; - 通过枚举和响应头
response.headers["content-disposition"]
来实现;
枚举方式
- 新建config 写入blobType的对象
1 | export const blobType = { |
- 引入,通过缓存中的文件名后缀确定type值;大致思路如下:
1 | // 1.引入枚举 |
Blob拓展
不仅是后端传来的文件流可以下载,字符串、对象、数组等任意类型都可以下载;
1 | // 下载txt格式的文件; |
现象:点击按钮,下载名为 fsl.txt
文件,内容为 “使用Blob对象下载文件”;
URL.createObjectURL拓展
使用URL.createObjectURL实现图片本地预览
这个方法是用来创建一个url
的,它的作用是把一个blob
对象转换成一个url
,这个url
可以用来下载文件,也可以用来预览文件;
1 | <body> |