前端文件流下载方法封装

目录

在Web开发中,我们经常会遇到需要处理文件下载的情况。特别是在处理API响应时,有时我们需要根据响应的内容类型和状态码来决定如何处理数据。本文将详细解析一段用于处理文件下载的JavaScript代码,该代码优先尝试将响应解析为JSON错误信息,若解析失败则按正常文件进行下载。

代码详解

  1. 从API响应中读取数据。
  2. 尝试将响应内容解析为JSON格式,以判断是否为错误信息。
  3. 根据解析结果决定继续处理还是直接下载文件。
  4. 如果确定为文件,则创建Blob对象并触发浏览器下载。
javascript 复制代码
// 下载文件并处理响应:优先尝试解析为 JSON 错误信息,若解析失败则按正常文件下载
const downLoadFileBlob = (res, fileName, type = 'application/vnd.ms-excel;charset=utf-8', validateErrorCode) => {
  const reader = new FileReader()
  // 将响应数据读取为文本,以便后续尝试 JSON 解析
  reader.readAsText(res.data)
  reader.onload = () => {
    try {
      // 尝试将响应文本解析为 JSON,判断是否为错误响应
      const response = JSON.parse(reader.result)
      console.log(response)
      // 若外部传入自定义错误码校验函数且校验通过,则直接返回,不再处理
      if (validateErrorCode && validateErrorCode(response.errorCode)) return
      // 错误码 401 表示登录失效,清空本地缓存并跳转登录页
      if (response.errorCode === 401) {
        localStorage.clear()
        window.location.href = '/login'
        return
      }
      // 若响应头指示为 JSON 文件,则主动抛出异常,进入 catch 分支进行文件下载
      if (res.headers['content-disposition'].indexOf('.json') !== -1) {
        throw new Error('文件解析失败,直接下载')
      } else {
        // 其他情况弹窗提示接口错误
        alert('接口错误')
      }
    } catch (err) {
      // 捕获异常后,进入正常文件下载流程
      console.log('下载正常处理')
      var downFileName = fileName
      try {
        // 从响应头 content-disposition 中提取文件名并解码
        downFileName = res.headers['content-disposition'].split(';')[1].split('=')[1]
        downFileName = decodeURIComponent(downFileName)
      } catch {
        // 若提取失败,使用默认传入的文件名
        console.log('file name is empty')
      }
      // 获取文件扩展名,用于决定 Blob 的 MIME 类型
      let fileArr = downFileName.split('.')
      let extensionName = fileArr[fileArr.length - 1]
      let blob
      if (extensionName === 'zip') {
        // ZIP 文件使用 Excel MIME 类型(兼容旧逻辑)
        blob = new Blob([res.data], { type: 'application/vnd.ms-excel;charset=utf-8' })
      } else if (extensionName === 'json') {
        // JSON 文件使用 JSON MIME 类型
        blob = new Blob([res.data], { type: 'application/json;charset=utf-8' })
      } else {
        // 其他文件使用外部传入或默认 MIME 类型
        blob = new Blob([res.data], { type: type })
      }
      // 创建 Blob URL 并触发浏览器下载
      var url = window.URL.createObjectURL(blob)
      var aLink = document.createElement('a')
      aLink.style.display = 'none'
      aLink.href = url
      aLink.setAttribute('download', downFileName)
      document.body.appendChild(aLink)
      aLink.click()
      // 下载完成后移除临时元素并释放 Blob URL
      document.body.removeChild(aLink)
      window.URL.revokeObjectURL(url)
    }
  }
}

方法接收四个参数,分别如下

  • res: API响应对象,包含dataheaders等属性。
  • fileName: 默认文件名。
  • type: Blob对象的MIME类型,默认值为'application/vnd.ms-excel;charset=utf-8'
  • validateErrorCode: 自定义的错误码校验函数。

FileReader对象用于异步读取BlobFile对象的内容。这里我们将响应数据res.data作为文本读取,以便后续尝试将其解析为JSON,为什么要做这部操作?直接解析Blob不就行了吗?现实中肯定不会这里简单,假如点击下载时登录失效,这个时候返回的时{errorCode : 401, errorMsg: '登录失效'},这个时候再按照Blob解析就会报错,不会退出登录,如果提供了validateErrorCode函数,则需要在validateErrorCode中自己处理错误,如果不提供,可以在下面处理公共错误。

如果JSON解析失败,证明时数据流了(不是JSON或数据流自行处理),从Content-Disposition头部提取文件名,并进行URL解码,创建Blob对象,创建隐藏的<a>标签,设置其href为Blob URL,并通过click事件触发下载,下载完成后,移除临时创建的<a>标签,并释放Blob URL。

本地开发可以拿到Content-Disposition字段,部署之后拿不到怎么办?请移步另一篇博文,前端无法获取响应头(如 Content-Disposition)的原因与解决方案

  1. API封装
javascript 复制代码
export const downloadFile = params => {
  return request.post(`${process.env.REACT_APP_API_URL}/api`, params, {
    // hiddenError: true,
    // noSpin: true,
    responseType: 'blob',
    uploadOrDownload: true
  })
}
  1. API调用
javascript 复制代码
downloadFile(params)
  .then(res => {
  		// 后续会补充downLoadFileBlob方法
    downLoadFileBlob(res)
  })
相关推荐
king王一帅4 小时前
Incremark Solid 版本上线:Vue/React/Svelte/Solid 四大框架,统一体验
前端·javascript·人工智能
智航GIS8 小时前
10.4 Selenium:Web 自动化测试框架
前端·python·selenium·测试工具
前端工作日常9 小时前
我学习到的A2UI概念
前端
徐同保9 小时前
为什么修改 .gitignore 后还能提交
前端
一只小bit9 小时前
Qt 常用控件详解:按钮类 / 显示类 / 输入类属性、信号与实战示例
前端·c++·qt·gui
Mr -老鬼10 小时前
前端静态路由与动态路由:全维度总结与实践指南
前端
颜酱10 小时前
前端必备动态规划的10道经典题目
前端·后端·算法
wen__xvn10 小时前
代码随想录算法训练营DAY10第五章 栈与队列part01
java·前端·算法
大怪v11 小时前
前端佬们!!AI大势已来,未来的上限取决你的独特气质!恭请批阅!!
前端·程序员·ai编程
Mr -老鬼12 小时前
功能需求对前后端技术选型的横向建议
开发语言·前端·后端·前端框架