theme: channing-cyan
更优雅的文件下载方式:前端异步下载文件实现方案
需求分析:
下载文件通常是通过打开一个非异步的get请求,但这样我们无法知道浏览器的下载进度以及什么时候下载完成(注意区分,浏览器知道和本应用知道的区别)。比如我们需要在下载过程添加自定义loading,以及下载完成后去做别的事。通过异步获取文件流,然后再下载文件的方式就能很好实现上述需求。
主要思路:
第一步,先通过异步请求(axios或xhr等),获取接口返回的字符流或blob,如果返回的是字符流,前端可自己通过new Blob() 转换成blob;
第二步,通过a标签下载blob;
第三部,下载完成,释放blob,将a标签从文档中移除。
注意:解决 ie 不支持直接下载 blob资源,可通过window.navigator.msSaveOrOpenBlob(blob, filename)实现
方案一:使用 axios 异步获取 blob
```js // 需要注意下载 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
js 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)) }
常规的同步下载文件方案
js download (url) { const a = document.createElement('a') a.href = url // 下载链接 a.download = 'filename' // 设置 download 属性告诉浏览器执行下载操作,可赋值文件名 a.click() }