文件下载是在开发中常见的一种需求,下面是在实际项目中使用的下载方案,记录一下
一、打开新页面下载文件
这是最简单的一种下载方案,通过打开新窗口的方法触发浏览器自带的下载功能,可以这样做
const url = "aaaa" // 后端提供的下载接口
// 1、通过window.open打开新窗口
window.open(url); // 打开新窗口,默认的target参数为_blank,在新窗口打开,也可以设置为_self之类的
// 2、也可以通过a标签打开新窗口
const a = document.createElement("a");
a.href = "aaaa";
a.download = "filename"; // 对比与window下载,特点在于可以设置下载下来的文件名
a.click();
这种方案是最简单的,但是弊端也很多:
- 1、对于部分浏览器可以直接展示的文件类型,比如音乐、视频、图片等,浏览器就不会执行下载操作,而是直接进行展示(由
response
的Content-Type
字段判断类型,image/png
或image/jpeg
等浏览器可以直接识别打开的文件,这样就不会执行下载事件。而像octet-stream
的二进制流数据,则是无法直接预览的) - 2、当接口访问异常或者参数问题等出现错误时,无法进行错误捕获,而是直接在新窗口显示出接口的报错信息,交互体验差
综上,这是一种简单,需保证接口调用结果正常,且在特定某些文件类型下可以使用的下载方案
二、通过文件流下载
这种方案主要分为两步,第一获取文件,第二下载文件
1、获取文件
获取文件主要是将请求接口返回的结果设置/转化为Blob(Binary Large Object): 二进制大数据对象
或者ArrayBuffer(又称类型化数组)
// 原生ajax
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = "blob"; // 设置返回结果为Blob对象
return new Promise(reslove => {
xhr.onload = () => {
if(xhr.status === 200) {
reslove(xhr.response)
}
}
})
xhr.send();
// axios
return new Promise((resolve, reject) => {
axios({
method:'get',
url,
responseType: 'arraybuffer' // 也可以设置为blob
}).then(data => {
resolve(data.data)
}).catch(error => {
reject(error.toString())
})
})
// fetch
return new Promise(reslove => {
fetch(url, {
method: "POST",
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(params)}).then(res => {
res.blob().then(data => {
reslove(data);
})
})
})
2、下载文件
获取文件以后,就可以开始下载文件
getFile().then(blob => { // file就是上面获取到的filedata
const a = document.createElement('a');
const url = window.URL.createObjectURL(blob);
a.href = url;
a.download = "fileName" ; // 设置下载下来的文件名
a.click();
window.URL.revokeObjectURL(url); // 释放通过调用 URL.createObjectURL() 创建的 URL 对象
})
这样一个文件就可以下载下来了
网友评论