持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情
前言
这里插播一则天气预告,近日受冷空气影响,全国各地出现大幅降温,一夜入冬,在此提醒广大掘友,温度骤降,注意保暖
的
同时
记得给我
言归正传
开发中经常会遇到下载文件的功能
一种是拿到后端提供的文件在资源服务器中的地址,使用 a 标签直接打开下载,或使用window.open / window.location.href
下载。
另一种方式是后端返回二进制文件流,前端对二进制文件流进行转换得到一个url通过a标签下载
这篇文章分享一下第二种方式的具体做法
一. 代码应用
完整方法:
const onDownload = (id) => {
API.getReportDownload(id).then((res) => {
const url = window.URL.createObjectURL(
new Blob([res.data], { type: 'application/octet-stream;charset=utf-8' })
)
const link = document.createElement('a')
link.style.display = 'none'
link.href = url
const fileName =
res.headers['content-disposition'].split("filename*=utf-8''")[1]
link.setAttribute('download', decodeURIComponent(fileName))
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
})
}
1. 获取二进制文件流
使用原生ajax或axios 正常调取接口的方法即可
需要注意,请求头中要添加 responseType: 'blob'
,将返回的二进制文件变为Blob对象,方便接下来使用JS进行操作
axios.get(url, {
params: params,
responseType: "blob" // 添加返回响应的类型
})
.then( res => {
console.log(res)
})
获取到的二进制流文件如图:
2. 转换为URL
const url = window.URL.createObjectURL(
new Blob([res.data], { type: 'application/octet-stream;charset=utf-8' })
)
将 Blob对象转换为 Blob url
3. 动态创建a标签,模拟点击下载
const link = document.createElement('a')
link.style.display = 'none'
link.href = url
// 这里读取header中提供的文件名,可根据需要决定是否前端写死或后端获取
const fileName =
res.headers['content-disposition'].split("filename*=utf-8''")[1]
link.setAttribute('download', decodeURIComponent(fileName))
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
这里需要注意,从header中获取文件部分信息时,如果使用某些封装过的axios请求,有可能将response中的头信息拦截掉,这时应该单独对下载接口做处理
二. 拓展延伸
1. Blob是什么?
在一般的 Web 开发中,很少会用到 Blob,但 Blob 可以满足一些场景下的特殊需求。Blob,Binary Large Object 的缩写,代表二进制类型的对象。Blob 的概念在一些数据库中有使用到,例如,MYSQL中的 BLOB 类型就表示二进制数据的容器。在 Web 中,Blob 类型的对象表示不可变的类似文件对象的原始数据。通俗点说,Blob对象是二进制数据,但它是类似文件对象的二进制数据,因此可以像操作 File 对象一样操作 Blob 对象,实际上,File 继承自Blob。
一直以来,JS都没有比较好的可以直接处理二进制的方法。而Blob的存在,允许我们可以通过JS直接操作二进制数据。
2. Blob API 简介
Blob
由一个可选的字符串 type
(通常是 MIME 类型)和 blobParts
组成:MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型,是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。·
常见的 MIME 类型有:超文本标记语言文本 .html text/html、PNG图像 .png image/png、普通文本 .txt text/plain 等。
3. Blob构造函数
Blob 构造函数的语法为:
var aBlob = new Blob(blobParts, options);
相关的参数说明如下:·
- blobParts:它是一个由 ArrayBuffer,ArrayBufferView,Blob,DOMString 等对象构成的数组。DOMStrings 会被编码为 UTF-8。
- options:一个可选的对象,包含以下两个属性:
-
- type —— 默认值为
""
,它代表了将会被放入到 blob 中的数组内容的 MIME 类型。 - endings —— 默认值为
"transparent"
,用于指定包含行结束符\n
的字符串如何被写入。它是以下两个值中的一个:"native"
,代表行结束符会被更改为适合宿主操作系统文件系统的换行符,或者"transparent"
,代表会保持 blob 中保存的结束符不变。
- type —— 默认值为
4. Blob 用作 URL
Blob 可以很容易的作为 <a>
、<img>
或其他标签的 URL,多亏了 type
属性,我们也可以上传/下载 Blob
对象。
Blob URL/Object URL 是一种伪协议,允许 Blob 和 File 对象用作图像,下载二进制数据链接等的 URL 源。在浏览器中,我们使用 URL.createObjectURL
方法来创建 Blob URL,该方法接收一个 Blob
对象,并为其创建一个唯一的 URL,其形式为 blob:<origin>/<uuid>
,对应的示例如下:
浏览器内部为每个通过 URL.createObjectURL
生成的 URL 存储了一个 URL → Blob 映射。因此,此类 URL 较短,但可以访问 Blob
。生成的 URL 仅在当前文档打开的状态下才有效。它允许引用 <img>
、<a>
中的 Blob
,但如果你访问的 Blob URL 不再存在,则会从浏览器中收到 404 错误。·
上述的 Blob URL 看似很不错,但实际上它也有副作用。虽然存储了 URL → Blob 的映射,但 Blob 本身仍驻留在内存中,浏览器无法释放它。映射在文档卸载时自动清除,因此 Blob 对象随后被释放。
但是,如果应用程序寿命很长,那不会很快发生。因此,如果我们创建一个 Blob URL,即使不再需要该 Blob,它也会存在内存中。
针对这个问题,我们可以调用 URL.revokeObjectURL(url)
方法,从内部映射中删除引用,从而允许删除 Blob(如果没有其他引用),并释放内存。接下来,我们来看一下 Blob 文件下载的具体示例。
总结
- 二进制文件流的下载概括为 把后端返回的二进制文件放在 Blob 里面,并且使用Blob 创建一个URL ,再通过JavaScript动态创建一个a标签,使用a标签打开这个 URL 。
- 通过拓展了解Blob后,其中的操作我们更容易理解。