vue+antdv a标签和axios对文件进行下载遇到的坑和二者的区别

52 阅读2分钟

a标签下载

这种方式下载比较简单,直接下载二进制数据流的文件 这种写法需要设置代理服务 downloadModel() 即后端同事给的路径比如: /api/downModel?id=${id} 不过前面需要补充完整 xx.xx.xx.xx:8080

  const a = document.createElement('a')
  a.href = downloadModel()
  document.body.appendChild(a)
  a.click()
  document.body.removeChild(a)

优点:简单,快速,文件名和格式均由后端提供

缺点:只能get方式,不可以传递data和自定义header(token等验证)

axios方式下载

axios方式由于后端返回的是数据流(如下图),需要转换成前端的blob对象

26d0f30cddc9404083f6ac1fdedbd86a.png

export function downloadByData(data: BlobPart, filename: string, mime?: string, bom?: BlobPart) {
  const blobData = typeof bom !== 'undefined' ? [bom, data] : [data]
  const blob = new Blob(blobData, { type: mime || 'application/octet-stream' })
  const blobURL = window.URL.createObjectURL(blob)
  const tempLink = document.createElement('a')
  tempLink.style.display = 'none'
  tempLink.href = blobURL
  tempLink.setAttribute('download', filename)
  if (typeof tempLink.download === 'undefined') {
    tempLink.setAttribute('target', '_blank')
  }
  document.body.appendChild(tempLink)
  tempLink.click()
  document.body.removeChild(tempLink)
  window.URL.revokeObjectURL(blobURL)
}
request.ts

export const exportData = data =>
  request({
     url: 'api/export',
     method: 'POST',
     data,
     responseType: 'blob',
})

调用

exportData().then(res => {
    downloadByData(res,'测试文件,'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
})

优点:可以使用post/get方式,可以携带请求头header

缺点:相对于a标签方式代码多一些,需要做blob转换,需要自定义文件名,以及文件类型要与后端保持一致,否则会导致下载下来无法打开

遇到的坑:

  1. axios方式中接口请求的responseType值一定设置‘blob’,或者其他类型文件;否则出现文件损坏打不开的情况

image.png

  1. 后端返回的是二进制数据流,输出如下图

1843694-20200824165855431-1782956585.png

所以在使用downloadByData()工具类时,第一个参数不能直接放入上图文件流,这样下载下来的文件也会出现损坏打不开的情况,而是axios的interceptors.response.use(response=>{})返回的第一个参数response,不能返回response.data即上图的blob对象;

tips:封装axios的request工具函数,判断接口返回的是否json还是数据流的方式:response.data instanceof Blob