Axios如何下载文件

341 阅读2分钟

如果在项目中第一次遇到下载、导出文件的时候,我们都会直接去请求API,期望会下载一个文件到本地,然后我们可以打开它。但是看到的结果却出乎意料。

接口返回的二进制流

并没有出现期望的情形,而是返回了一堆“乱码”。

AJAX无法下载文件的原因

下载其实是浏览器的内置事件,浏览器的 GET请求(frame、a)、 POST请求(form)具有如下特点:

  • response会交由浏览器处理
  • response内容可以为二进制文件、字符串等

但是AJAX请求不一样:

  • response会交由 Javascript 处理
  • response内容只能接收字符串才能继续处理

因此,AJAX本身无法触发浏览器的下载功能。

Axios如何实现下载

  • 发送请求
  • 获得response
  • 通过response判断返回是否为流文件
  • 如果是文件则在页面中插入frame/a标签
  • 利用frame/a标签实现浏览器的get下载

首先封装一个download方法,用于发送请求

// request.js

import Axios form 'axios';

/*
 * @params {string} url 请求地址
 * @params {object} resOpts 请求配置参数
 */
const download = (url, resOpts = {}) => {
  const { type = 'get', data = '' } = resOpts
  const queryArgs = {
    url,
    method: type,
    data,
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json; charset=utf-8',
      withCredentials: true,
    },
  }
  // tips: 这里直接返回的是response整体!
  return Axios.request(queryArgs).catch(err => console.log(err))
}

...

拿到response之后我们需要将流文件通过浏览器下载

// utils.js

export function convertRes2Blob(response) {
  // 提取文件名
  const fileName = response.headers['content-disposition'].match(
    /filename=(.*)/
  )[1]
  // 将二进制流转为blob
  const blob = new Blob([response.data], { type: 'application/octet-stream' })
  if (typeof window.navigator.msSaveBlob !== 'undefined') {
    // 兼容IE,window.navigator.msSaveBlob:以本地方式保存文件
    window.navigator.msSaveBlob(blob, decodeURI(filename))
  } else {
    // 创建新的URL并指向File对象或者Blob对象的地址
    const blobURL = window.URL.createObjectURL(blob)
    // 创建a标签,用于跳转至下载链接
    const tempLink = document.createElement('a')
    tempLink.style.display = 'none'
    tempLink.href = blobURL
    tempLink.setAttribute('download', decodeURI(filename))
    // 兼容:某些浏览器不支持HTML5的download属性
    if (typeof tempLink.download === 'undefined') {
      tempLink.setAttribute('target', '_blank')
    }
    // 挂载a标签
    document.body.appendChild(tempLink)
    tempLink.click()
    document.body.removeChild(tempLink)
    // 释放blob URL地址
    window.URL.revokeObjectURL(blobURL)
  }
}

缺点

  • download请求方法与convertRes2Blob处理文件下载的方法,需要分开调用
  • download使用独立的实例,不能公用一个axios,基础配置需要单独维护