前端文件下载常用方式详解

在前端开发中,实现文件下载是常见的需求。根据不同的场景,我们可以选择不同的方法来实现文件流的下载。本文介绍三种常用的文件下载方式:

  • 使用 axios 发送 JSON 请求下载文件流
  • 使用 axios 发送 FormData 请求下载文件流
  • 使用原生 form 表单提交下载文件流

一、使用 Axios 下载文件流(JSON 格式参数)

✅ 适用场景:

适用于需要通过 POST 请求发送 JSON 数据给后端以获取文件流的情况。

⚠️ 注意事项:

  • 设置 responseType: 'blob'
  • 使用 Blob 对象处理响应数据。
  • 动态获取文件名需依赖 Content-Disposition 头部字段,部分浏览器可能不支持,需服务器配置允许跨域访问该头部。

🧩 示例代码:

javascript 复制代码
axios({
  url: 'https://localhost/download/test',
  method: 'post',
  data: {
    headers: ["姓名", "年龄", "城市"],
    data: [{
      "姓名": "张三",
      "年龄": 25,
      "城市": "北京"
    }],
    fileName: "99"
  },
  responseType: 'blob',
  withCredentials: true
}).then(response => {
  // 获取文件名
  let filename = '默认文件.xlsx';
  const disposition = response.headers['content-disposition'];
  if (disposition && disposition.indexOf('filename=') !== -1) {
    filename = disposition.split('filename=')[1].replace(/"/g, '');
    try {
      filename = decodeURIComponent(filename);
    } catch (e) {
      filename = unescape(filename);
    }
  }

  // 创建 Blob 并触发下载
  const blob = new Blob([response.data], { type: response.headers['content-type'] });
  const url = window.URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = url;
  link.download = filename;
  document.body.appendChild(link);
  link.click();
  window.URL.revokeObjectURL(url);
  document.body.removeChild(link);
});

二、使用 Axios 下载文件流(FormData 格式参数)

✅ 适用场景:

适用于需要传递键值对形式的数据(如上传文件)或模拟表单提交的场景。

⚠️ 注意事项:

  • 设置请求头为 'application/x-www-form-urlencoded'
  • 使用 FormData 构造请求体。
  • 同样需要处理动态文件名。

🧩 示例代码:

javascript 复制代码
const formData = new FormData();
formData.append("key", "value");

axios({
  url: 'http://localhost/api/download',
  method: 'post',
  data: formData,
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  responseType: 'blob',
  withCredentials: true
}).then(response => {
  const disposition = response.headers['content-disposition'];
  let filename = '默认文件.xlsx';

  if (disposition && disposition.includes('filename=')) {
    filename = disposition.split('filename=')[1].replace(/"/g, '');
    try {
      filename = decodeURIComponent(filename);
    } catch (e) {
      filename = unescape(filename);
    }
  }

  const blob = new Blob([response.data], { type: response.headers['content-type'] });
  const url = window.URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = url;
  link.download = filename;
  document.body.appendChild(link);
  link.click();
  window.URL.revokeObjectURL(url);
  document.body.removeChild(link);
});

三、使用原生 Form 表单提交下载文件流

✅ 适用场景:

适用于不需要 JavaScript 控制、直接通过表单提交参数并由后端返回文件流的场景。

⚠️ 注意事项:

  • 需要手动创建隐藏的 <form> 元素。
  • 不适合处理 Blob 文件流(无法控制下载行为)。
  • 不支持异步操作,页面会跳转。

🧩 示例代码:

javascript 复制代码
const paraData = { id: 1212, name: '测试名' };
const formActionUrl = gateUrl + '/api/dictData/downloadDictDataList';

const form = document.createElement('form');
form.style.display = 'none';
form.action = formActionUrl;
form.method = 'post';
form.enctype = 'application/x-www-form-urlencoded'; // 可选

document.body.appendChild(form);

for (let key in paraData) {
  if (paraData.hasOwnProperty(key)) {
    const input = document.createElement('input');
    input.type = 'hidden';
    input.name = key;
    input.value = paraData[key];
    form.appendChild(input);
  }
}

form.submit(); // 提交表单
form.remove(); // 移除表单

✅ 总结对比

方法 是否支持 JSON 是否支持文件下载 是否支持动态文件名 是否异步 是否推荐
Axios + JSON ✅(依赖响应头) ✅ 推荐
Axios + FormData ❌(自动转换) ✅ 推荐
原生 Form ⚠️ 视情况

🔁 补充建议

  1. 封装统一下载工具函数:将通用逻辑提取成工具函数,提高复用性。
  2. 兼容中文文件名:建议后端统一使用 UTF-8 编码文件名,避免前端解析困难。
  3. 错误处理增强 :添加 .catch() 捕获异常并提示用户。
  4. 取消请求机制 :对于大文件或长时间请求,可考虑加入取消功能(如 CancelTokenAbortController)。
相关推荐
后海 0_o6 分钟前
2025前端微服务 - 无界 的实战应用
前端·微服务·架构
Scabbards_8 分钟前
CPT304-2425-S2-Software Engineering II
前端
小满zs14 分钟前
Zustand 第二章(状态处理)
前端·react.js
程序猿小D16 分钟前
第16节 Node.js 文件系统
linux·服务器·前端·node.js·编辑器·vim
萌萌哒草头将军18 分钟前
🚀🚀🚀Prisma 发布无 Rust 引擎预览版,安装和使用更轻量;支持任何 ORM 连接引擎;支持自动备份...
前端·javascript·vue.js
狼性书生32 分钟前
uniapp实现的简约美观的星级评分组件
前端·uni-app·vue·组件
书语时35 分钟前
ES6 Promise 状态机
前端·javascript·es6
拉不动的猪1 小时前
管理不同权限用户的左侧菜单展示以及权限按钮的启用 / 禁用之其中一种解决方案
前端·javascript·面试
西陵1 小时前
前端框架渲染DOM的的方式你知道多少?
前端·javascript·架构
小九九的爸爸1 小时前
我是如何让AI帮我还原设计稿的
前端·人工智能·ai编程