更优雅的文件下载方式:前端异步下载文件实现方案
更优雅的文件下载方式:前端异步下载文件实现方案
需求分析:
下载文件通常是通过打开一个非异步的get请求,但这样我们无法知道浏览器的下载进度以及什么时候下载完成(注意区分,浏览器知道和本应用知道的区别)。比如我们需要在下载过程添加自定义loading,以及下载完成后去做别的事。通过异步获取文件流,然后再下载文件的方式就能很好实现上述需求。
主要思路:
第一步,先通过异步请求(axios或xhr等),获取接口返回的字符流或blob,如果返回的是字符流,前端可自己通过new Blob() 转换成blob;
第二步,通过a标签下载blob;
第三部,下载完成,释放blob,将a标签从文档中移除。
注意:解决 ie 不支持直接下载 blob资源,可通过window.navigator.msSaveOrOpenBlob(blob, filename)实现
方案一:使用 axios 异步获取 blob
// 需要注意下载 excel 时, axios 或 xhr 请求需要将 xhr.responseType = "blob"
// 否则下载后的 excel 会打不开
// 返回类型blob
downloadExcel (params) {
// 封装过的 axios
this.$api.downloadExcel(params).then(res => {
let filename = res.headers['filename']
// const blob = new Blob([res.data]) // 将字符流转换为 blob对象
blobDownload(res.data, decodeURIComponent(filename))
}).finally(() => {
this.loading = false
})
},
/**
* 下载文件:下载 blob 对象形式的文件
* @param blob
* @param filename
*/
export function blobDownload (blob, filename = '文件.txt') {
let url = window.URL.createObjectURL(blob)
// 解决 ie 不支持直接下载 blob资源
if ('msSaveOrOpenBlob' in navigator) {
window.navigator.msSaveOrOpenBlob(blob, filename)
return
}
let link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.download = filename
document.body.appendChild(link)
link.click()
document.body.removeChild(link) // 下载完成移除元素
window.URL.revokeObjectURL(url) // 释放掉blob对象
}
// 创建axios实例
const service = axios.create({
headers: {
'kms-token': localStorage.getItem('token') || ''
},
baseURL: config.ip,
timeout: 2 * 600000,
withCredentials: true // 表示跨域请求时是否需要使用凭证,开启后,后端服务器要设置允许开启
})
// request拦截器
service.interceptors.request.use(
config => {
const token = localStorage.getItem('token')
if (config.url === '/api/excel/upload/knowledge/download') {
// 返回类型blob,不设置会打不开 excel
config.responseType = 'blob'
// config.headers['Content-Type'] = 'application/x-download'
}
return config
},
error => {
// console.warn(error)
return Promise.reject(error)
}
)
写法二:使用 xhr 异步获取 blob
downloadExcel2 (params) {
const token = localStorage.getItem('token') || ''
const url = 'http://192.168.0.0' + ':8079/' + '/api/excel/download'
let xhr = new XMLHttpRequest()
// POST方式
xhr.open('POST', url + '?timeStamp=' + new Date().getTime(), true)
xhr.setRequestHeader('Cache-Control', 'no-cache')
xhr.setRequestHeader('Content-type', 'application/json')
xhr.setRequestHeader('token', token)
// 返回类型blob,不设置会打不开 excel
xhr.responseType = 'blob'
// 定义请求完成的处理函数,请求前也可以增加加载框/禁用下载按钮逻辑
xhr.onload = function () {
// 请求完成
if (this.status === 200) {
let blob = this.response
let reader = new FileReader()
// 转换为base64,可以直接放入a表情href
reader.readAsDataURL(blob)
reader.onload = function (e) {
// 转换完成,创建一个a标签用于下载
let a = document.createElement('a')
a.download = '收支清单.xlsx'
a.href = e.target.result
a.click()
}
}
}
xhr.send(JSON.stringify(params))
}
常规的同步下载文件方案
download (url) {
const a = document.createElement('a')
a.href = url // 下载链接
a.download = 'filename' // 设置 download 属性告诉浏览器执行下载操作,可赋值文件名
a.click()
}
转载自:https://juejin.cn/post/7081618559792578590