前端实现文件下载的完整流程

文章目录

在企业项目中,经常会遇到 导出 Excel、下载 PDF、下载日志文件等需求

很多人知道可以通过 fetchaxios 请求接口,但 为什么请求后就能触发浏览器下载?

下面将从 前端请求 → 后端返回 → 浏览器保存文件 的完整链路,详解其中实现原理。

一、文件下载的整体流程

一个完整的文件下载流程通常如下:

复制代码
用户点击导出
     ↓
前端发送请求(fetch / axios)
     ↓
后端读取服务器文件
     ↓
后端返回文件流(binary stream)
     ↓
前端将响应转换为 Blob
     ↓
创建下载链接
     ↓
浏览器触发下载

简单来说就是:

请求文件 → 转换为 Blob → 创建下载链接 → 触发下载

二、前端发送下载请求

例如前端代码:

javascript 复制代码
const downloadInfoPubFile = async (data) => {
  const url = "/api/common/file/download";

  const response = await fetch(url, {
    method: "POST",
    headers: {
      "Content-Type": "application/json;charset=utf-8",
      Authorization: `Bearer ${token}`
    },
    body: JSON.stringify(data)
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  const blob = await response.blob();

  return { blob };
};

请求接口:

复制代码
POST /api/common/file/download

请求参数:

json 复制代码
{
  "filePath": "/upload/excel/report.xlsx"
}

这一步的作用是:

告诉后端需要下载哪个文件。

三、后端返回文件流

后端收到请求后,一般会做三件事:

1️⃣ 根据 filePath 找到服务器文件

2️⃣ 设置响应头

3️⃣ 返回文件流

例如:

复制代码
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Content-Disposition: attachment; filename="report.xlsx"

关键是 Content-Disposition

复制代码
Content-Disposition: attachment

表示:

浏览器应该下载这个文件,而不是直接展示。

后端返回的数据实际上是:

复制代码
Binary Stream(二进制流)

例如:

复制代码
PK....
.......

(Excel 本质是 zip 文件)

四、前端将文件流转换为 Blob

浏览器收到响应后:

javascript 复制代码
const blob = await response.blob();

此时浏览器会把 二进制数据转换为 Blob 对象

Blob 可以理解为:

浏览器中的二进制文件对象。

例如:

复制代码
Blob {
  size: 15324
  type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}

Blob 常用于表示:

  • Excel
  • PDF
  • 图片
  • 视频
  • 任意二进制文件

五、生成浏览器可访问的文件 URL

Blob 不能直接下载,需要先生成一个 URL:

javascript 复制代码
const url = window.URL.createObjectURL(blob);

浏览器会生成类似:

复制代码
blob:http://localhost:5173/3fa85f64-5717

这个地址指向 浏览器内存中的文件数据

六、创建下载链接触发浏览器下载

浏览器下载文件的核心其实只有一个:

复制代码
<a download>

代码实现:

javascript 复制代码
const link = document.createElement("a");
link.href = url;
link.download = "report.xlsx";

document.body.appendChild(link);
link.click();
document.body.removeChild(link);

浏览器实际执行的是:

html 复制代码
<a href="blob:xxxx" download="report.xlsx"></a>

当执行 link.click() 时:

浏览器就会自动下载文件。

七、完整下载代码示例

javascript 复制代码
const handleExport = async (record) => {
  const res = await downloadInfoPubFile({
    filePath: record.filePath
  });

  const url = window.URL.createObjectURL(res.blob);

  const link = document.createElement("a");
  link.href = url;
  link.download = "download.xlsx";

  document.body.appendChild(link);
  link.click();

  document.body.removeChild(link);

  window.URL.revokeObjectURL(url);
};

注意最后一行:

javascript 复制代码
URL.revokeObjectURL(url)

作用是:

释放浏览器内存。

否则大量下载可能造成 内存泄漏

八、为什么不直接使用 window.open 下载?

很多人会写:

javascript 复制代码
window.open("/api/download");

这种方式在实际项目中问题很多:

1 不能携带 Token

企业系统基本都有登录认证:

复制代码
Authorization: Bearer token

window.open 无法设置请求头。

2 不支持 POST 请求

很多下载接口需要:

复制代码
POST

而浏览器地址栏只能:

复制代码
GET

3 无法处理错误

如果接口返回:

json 复制代码
{
  "message": "文件不存在"
}

用户只会看到:

复制代码
下载失败

但不会有明确提示。

使用 fetch 可以:

复制代码
统一错误处理

九、JSON + Base64 下载方式

有些接口不会直接返回文件流,而是返回:

json 复制代码
{
  "filename": "report.xlsx",
  "data": "base64..."
}

前端需要先解码:

javascript 复制代码
const byteCharacters = atob(base64Data);
const byteNumbers = new Array(byteCharacters.length);

for (let i = 0; i < byteCharacters.length; i++) {
  byteNumbers[i] = byteCharacters.charCodeAt(i);
}

const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray]);

然后再执行下载。

总结

前端文件下载的核心步骤只有四步:

复制代码
1 发送请求获取文件
2 将响应转换为 Blob
3 创建 Blob URL
4 使用 a 标签触发下载

完整流程:

复制代码
前端 fetch 请求
      ↓
后端返回文件流
      ↓
response.blob()
      ↓
URL.createObjectURL()
      ↓
<a download>
      ↓
浏览器下载文件

企业项目最佳实践:

复制代码
fetch / axios + Blob 下载

优点:

  • 支持 Token 认证
  • 支持 POST 请求
  • 可以统一处理错误
  • 可以动态文件名
  • 支持各种文件类型

因此,这种方式已经成为 前端文件下载的标准实现方案


👉点击进入 我的网站

相关推荐
tedcloud1233 小时前
UI-TARS-desktop部署教程:构建AI桌面自动化系统
服务器·前端·人工智能·ui·自动化·github
UXbot6 小时前
AI原型设计工具如何支持团队协作与快速迭代
前端·交互·个人开发·ai编程·原型模式
ZC跨境爬虫7 小时前
跟着MDN学HTML_day_48:(Node接口)
前端·javascript·ui·html·音视频
PieroPc8 小时前
CAMWATCH — 局域网摄像头监控系统 Fastapi + html
前端·python·html·fastapi·监控
巴巴博一9 小时前
2026 最新:Trae / Cursor 一键接入 taste-skill 完整教程(让 AI 前端告别“AI 味”)
前端·ai·ai编程
kyriewen9 小时前
半夜三点线上崩了,AI替我背了锅——用AI排错,五分钟定位三年老bug
前端·javascript·ai编程
kyriewen10 小时前
我让 AI 当了 24 小时全年无休的“毒舌考官”
前端·ci/cd·ai编程
hexu_blog10 小时前
vue+java实现图片批量压缩
java·前端·vue.js
IT_陈寒10 小时前
为什么你应该学习JavaScript?
前端·人工智能·后端
lifejump11 小时前
Empire(帝国)CMS 7.5 XSS注入
前端·安全·xss