记一次前端文件下载处理过程

Axios 请求拦截处理

TypeScript 复制代码
  // 响应拦截器
  instance.interceptors.response.use(async (response: AxiosResponse<customRes, any>): Promise<any> => {
    // 文件流处理
    if (response.config.responseType == "blob") return Promise.resolve(response);
  
    return Promise.resolve(response.data);
  }, responseErrorHandle)

当响应的数据类型是文件流(Blob)时,拦截器直接返回了一个包含 response 的 Promise,以便在调用这个接口的地方能够获取到文件流并进一步处理。

请求方法处理

通过 Axios 请求文件流(Blob)并进行文件下载的函数。

请求服务器返回的文件流数据,并通过浏览器的下载机制将其保存到本地文件。

设置响应类型为 Blob 是为了告知服务器返回的数据是二进制流,方便后续在客户端进行文件下载。

TypeScript 复制代码
  /**
   * 返回文件流测试
   */
  export const getFile = () => {
    instance.get('/test/file/stream', {
      responseType: "blob", // 设置响应类型为blob
      params: {}
    }).then((response) => {
      // 处理下载文件
      const url = window.URL.createObjectURL(new Blob([response.data]));
      const link = document.createElement("a");
      link.href = url;
      link.setAttribute("download", getFileNameFromHeaders(response)); // 设置下载的文件名和扩展名
      link.click();
    })
  }

从headers中取出文件名方法封装

TypeScript 复制代码
  // 文件名处理
  export const getFileNameFromHeaders = (response: AxiosResponse) => {
    // 从响应头中获取Content-Disposition信息
    const contentDisposition = response.headers['content-disposition'];
  
    // 使用正则表达式匹配文件名
    const match = /filename="(.*)"/.exec(contentDisposition);
  
    // 获取匹配的文件名
    return match ? decodeURI(match[1]) : 'unknown'
  }
  1. instance.get('/test/file/stream', {...}):
    • 使用 Axios 的 get 方法向服务器端发送 GET 请求,请求的地址是 '/test/file/stream'。
  2. responseType: "blob":
    • 在请求配置中设置 responseType 为 "blob",表示期望服务器响应的数据是二进制数据(Blob 对象)。
  3. .then((response) => {...}):
    • 使用 Promise 的 .then 处理请求成功的回调函数,response 包含了从服务器返回的 Blob 对象。
  4. window.URL.createObjectURL(new Blob([response.data])):
    • 通过 window.URL.createObjectURL 创建一个临时的 URL,该 URL 表示了从服务器返回的 Blob 对象的内容。这个 URL 通常用于创建下载链接。
  5. const link = document.createElement("a");:
    • 创建一个 <a> 元素,用于模拟文件下载。
  6. link.href = url;:
    • 将刚刚创建的 URL 赋值给 <a> 元素的 href 属性。
  7. link.setAttribute("download", getFileNameFromHeaders(response));:
    • 设置 <a> 元素的 download 属性为从服务器响应头中获取的文件名。这里使用 getFileNameFromHeaders 的函数,它可能用于从响应头中获取文件名,确保文件名包含在 Content-Disposition 头中。
  8. link.click();:
    • 模拟点击 <a> 元素,触发文件下载。

整个流程的目的是通过 Axios 请求获取服务器端返回的文件流,然后使用 Blob 对象创建一个临时的 URL,并通过创建 <a> 元素模拟点击以触发文件下载。

网络服务处理

返回文件流的接口

JavaScript 复制代码
  // 服务端返回文件流,并将文件名通过 attachment 返回
  router.get('/file/stream', async (ctx, next) => {
      const filePath = path.join(__dirname, '../upload/file/测试表格.xlsx');
      // 设置响应头,告诉浏览器文件名
      ctx.attachment(encodeURI('测试表格.xlsx'));
      // 读取文件流并设置为响应体
      ctx.body = await fs.createReadStream(filePath);
  })

跨域配置

允许前端访问 Content-Disposition

JavaScript 复制代码
app.use(cors({
    exposeHeaders: ['Content-Disposition'],
    credentials: true,  // 允许携带cookies
}));

总结

服务端返回文件流,并将文件名通过 attachment 返回,文件名会被携带在 Content-Disposition中。

前端通过 getFileNameFromHeaders 方法取出 文件名

前端通过 window.URL.createObjectURL(new Blob(response.data)) 创建一个可用于浏览器中的文件下载的 URL

相关推荐
沙蒿同学7 小时前
不引 Ghostscript:我用纯 Go 给 PDF 做了一场「压缩手术」
前端·后端·github
Linux_cy7 小时前
服务器管理工具哪个好用?我用了七八个
运维·服务器·javascript·python·ssh·面板·gmssh
变与不变8067 小时前
jQuery细节以及使用应用场景
前端·javascript·jquery
SailingCoder9 小时前
【封闭结束1】端到端交付:Agent 一次请求如何走完全链路
前端·安全·ai·面试·agent·harness
风骏时光牛马11 小时前
AI多模块协同自动化工作流
前端
zhangminghuan11 小时前
前端面试应对技巧
前端·面试·职场和发展
计算机魔术师12 小时前
潜伏14年的PHP致命洞,AI跑两天就交卷了
前端
IT_陈寒12 小时前
Vue的这个响应式陷阱我居然现在才发现
前端·人工智能·后端
Python自动化直播13 小时前
智能脚本批量管理拆开看:导入、导出、重写、试听
前端·python·ai·秒播