JavaScript 的 axios 实现文件下载功能

打印 上一主题 下一主题

主题 989|帖子 989|积分 2967

用 JavaScript 的 axios 实现文件下载功能,咱们要分几个步骤来搞定它!最重要的部分是处理 二进制数据,可以天生一个进度检测,然后把它生存为文件。


  • 文件名的获取
  • 二进制数据获取
  • 创建下载链接

  1. const axios = require('axios');
  2. const getFileNameFromContentDisposition = (contentDisposition) => {
  3.   const fileNameMatch = contentDisposition && contentDisposition.match(/filename="?([^"]+)"?/);
  4.   return fileNameMatch ? fileNameMatch[1] : null;
  5. };
  6. const getFileNameFromUrl = (fileUrl) => {
  7.   return fileUrl.split('/').pop();
  8. };
  9. const downloadFile = async (fileUrl, defaultFileName = 'downloaded-file') => {
  10.   try {
  11.     const response = await axios({
  12.       url: fileUrl,
  13.       method: 'GET',
  14.       responseType: 'blob', // 以二进制方式接收数据
  15.       onDownloadProgress: (progressEvent) => {
  16.         // progressEvent 包含了下载进度信息
  17.         const total = progressEvent.total; // 文件总大小
  18.         const loaded = progressEvent.loaded; // 已经下载的部分
  19.         // 计算进度百分比
  20.         const percentage = Math.floor((loaded / total) * 100);
  21.         
  22.         // 显示进度(可替换为实际的进度条)
  23.         console.log(`下载进度:${percentage}%`);
  24.       }
  25.     });
  26.     // 获取文件名
  27.     let fileName = getFileNameFromContentDisposition(response.headers['content-disposition']) || getFileNameFromUrl(fileUrl) || defaultFileName;
  28.     // 创建 Blob 对象
  29.     const blob = new Blob([response.data], { type: response.headers['content-type'] });
  30.    
  31.     // 创建 Blob URL
  32.     const blobUrl = window.URL.createObjectURL(blob);
  33.     // 创建 <a> 元素并触发下载
  34.     const link = document.createElement('a');
  35.     link.href = blobUrl;
  36.     link.download = fileName;
  37.     // 将 <a> 元素添加到 DOM 并触发点击
  38.     document.body.appendChild(link);
  39.     link.click();
  40.     // 移除 <a> 元素
  41.     document.body.removeChild(link);
  42.     // 释放 Blob URL
  43.     window.URL.revokeObjectURL(blobUrl);
  44.   } catch (error) {
  45.     console.error('文件下载失败: ', error);
  46.   }
  47. };
  48. // 调用下载函数,传入文件URL
  49. downloadFile('https://example.com/path/to/your/file.pdf');
复制代码

从代码优化和健壮性角度出发,我们可以把这三种文件名获取方式联合起来,优先从相应头中提取文件名,然后如果没有Content-Disposition头,再从 URL 提取文件名,最后可以提供一个默认文件名作为兜底方案。此外,考虑到代码可读性和可维护性,上面代码做一些清晰的封装与优化处理。

  • 文件名获取逻辑封装

    • getFileNameFromContentDisposition:专门用于从 Content-Disposition 头部提取文件名,使用正则匹配,考虑了有引号和没有引号的情况。
    • getFileNameFromUrl:用于从 URL 提取文件名,确保从路径最后一部分获取到文件名。
    • 优先级:先从 Content-Disposition 获取文件名,如果没有,再从 URL 提取,最后使用默认文件名。

  • 默认文件名

    • 提供了 defaultFileName 参数,确保当无法从相应头和 URL 获取文件名时,仍旧有一个合理的文件名用于下载。

  • 非常处理

    • 使用 try-catch 包围整个下载过程,确保即使出现网络或其他问题,错误也能被捕获并输出到控制台,而不会影响页面的其他功能。

  • 内存管理

    • 确保 window.URL.revokeObjectURL(blobUrl) 在文件下载后被调用,开释 Blob URL,防止内存泄漏。

健壮性和可扩展性:



  • 健壮性:我们确保了即使某个步骤失败,代码也能继续运行。文件名无法从相应头或 URL 获取时,始终有一个默认文件名兜底。
  • 可扩展性:如果未来须要支持更多的文件名获取逻辑或更复杂的相应头处理,只需修改或添加新的获取方式即可,而不会影响整体代码结构。

为什么可以立即移除 <a> 元素?

点击事件:link.click() 触发后,浏览器会处理下载请求,下载任务已经在后台举行。<a> 元素的点击只是用来启动这个过程。
DOM 操作与事件的异步性:浏览器在处理用户点击和下载之间有肯定的时间差,移除 <a>元素是在 click 事件完成后举行,不会影响已经发出的下载请求。

为什么不消关注文件范例

下载文件的前置条件中不依靠于文件的具体范例,现实上,代码对文件范例的处理是比力通用的。这是通过以下几个方面实现的:
1. 相应范例的设置



  • 在 Axios 请求中,我们将 responseType 设置为 'blob',这意味着无论文件范例是什么,浏览器都将其作为 Blob 对象处理。Blob 可以表示二进制数据,而不关心其具体的内容范例。
2. Content-Type 的使用



  • 在创建 Blob 时,我们根据相应头中的 Content-Type 来设置 Blob 的 MIME 范例。这使得文件在下载时能够被浏览器正确识别和处理:
    1. const blob = new Blob([response.data], { type: response.headers['content-type'] });
    复制代码
3. 文件名的获取



  • 文件名的获取逻辑同样不依靠于文件范例。我们根据 Content-Disposition 头部或 URL 提取文件名。这样无论是 PDF、图片、文本文件还是其他任何范例的文件,代码都能正确天生文件名并完成下载。
4. 下载时的文件处理



  • 浏览器会根据 Blob 的 MIME 范例和下载时提供的文件名来决定如何处理文件。比方,对于 PDF 文件,浏览器会使用 PDF 阅读器打开它,而对于图片文件则会直接展示。
注意事项



  • 特殊文件范例处理:固然以上代码可以处理多种范例的文件,但某些文件(如 HTML 文件)可能会受到浏览器的默认行为影响。比方,某些文件可能会直接在浏览器中打开,而不是下载。这是由浏览器对特定 MIME 范例的处理决定的,无法通过代码控制。
  • 服务器的设置:如果服务器没有正确设置 Content-Disposition 头部,或者对某些文件范例没有指定 MIME 范例,可能会导致文件下载或命名不正确。因此,确保服务器正确设置是关键。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

民工心事

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表