likes
comments
collection
share

更优雅的文件下载方式:前端异步下载文件实现方案

作者站长头像
站长
· 阅读数 18

更优雅的文件下载方式:前端异步下载文件实现方案

需求分析:

下载文件通常是通过打开一个非异步的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
评论
请登录