蓝戒博客

  • 首页
  • 研发说
  • 架构论
  • 效能录
  • AI谈
  • 随笔集
智构苍穹
融合 AI、架构与工程实践,沉淀方法论,构建可持续的技术价值。
  1. 首页
  2. 研发说
  3. 正文

吃透大文件分片上传:原理、方案与最佳实践

2026年1月12日 924点热度 0人点赞 0条评论

在企业级 Web 应用中,大文件上传几乎是一个绕不开的话题:视频、日志包、模型文件、设计稿、数据集……
当文件体积从几十 MB 上升到 GB 级别,传统的上传方式往往会彻底失效。

本文将系统讲清楚:

  • 大文件上传会遇到哪些核心问题
  • 分片上传的整体设计思路
  • 秒传 / 断点续传 / 并发控制如何实现
  • 前后端核心实现代码
  • 线上落地的最佳实践

一、为什么普通上传在大文件面前会失败?

1. 请求不稳定,失败率高

  • HTTP 请求时间过长
  • 网络抖动、代理超时、浏览器中断
  • 任意一次失败都要 重头再来

2. 用户体验极差

  • 上传过程中页面刷新或关闭 → 全部丢失
  • 无法展示准确进度
  • 失败后不可恢复

3. 服务端压力巨大

  • 单请求占用连接时间过长
  • 内存 / 带宽被长时间占用
  • 高并发下容易拖垮服务

二、大文件上传的核心解决思路

核心思想:分而治之

把一个大文件,拆成多个可控的小文件,分别上传,最后在服务端合并。

标准分片上传流程

选择文件
   ↓
文件切片(chunk)
   ↓
并发上传分片
   ↓
记录已上传分片
   ↓
全部完成后通知服务端合并

三、一个成熟的分片上传方案应具备哪些能力?

能力说明
分片上传将大文件拆分为多个 chunk
断点续传已上传的分片不再重复上传
秒传文件已存在时直接完成
并发控制控制同时上传的分片数量
失败重试单分片失败可重试
服务端合并确保合并顺序和完整性

四、整体架构设计

前后端职责划分

前端负责:

  • 文件切片
  • 计算文件唯一标识(hash)
  • 分片并发上传
  • 失败重试
  • 上传进度控制

后端负责:

  • 校验文件是否已存在(秒传)
  • 记录已上传分片
  • 接收分片并持久化
  • 按顺序合并文件
  • 清理临时分片

五、前端核心实现(浏览器)

1️⃣ 文件切片

TypeScript
/**
 * 将文件切分为固定大小的分片
 */
function createFileChunks(file: File, chunkSize = 5 * 1024 * 1024) {
  const chunks: Blob[] = [];
  let start = 0;

  while (start < file.size) {
    chunks.push(file.slice(start, start + chunkSize));
    start += chunkSize;
  }

  return chunks;
}

2️⃣ 计算文件 Hash(用于秒传 & 断点续传)

TypeScript
/**
 * 计算文件 hash(基于 Web Worker + SparkMD5 更优)
 */
async function calculateHash(file: File): Promise<string> {
  const buffer = await file.arrayBuffer();
  const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
  return Array.from(new Uint8Array(hashBuffer))
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');
}

3️⃣ 上传单个分片

TypeScript
/**
 * 上传单个分片
 */
function uploadChunk(
  chunk: Blob,
  index: number,
  hash: string
) {
  const formData = new FormData();
  formData.append('chunk', chunk);
  formData.append('index', index.toString());
  formData.append('hash', hash);

  return fetch('/upload/chunk', {
    method: 'POST',
    body: formData,
  });
}

4️⃣ 并发上传控制(重点)

TypeScript
/**
 * 控制并发上传
 */
async function uploadChunksWithLimit(
  tasks: (() => Promise<any>)[],
  limit = 4
) {
  const executing: Promise<any>[] = [];

  for (const task of tasks) {
    const p = task();
    executing.push(p);

    if (executing.length >= limit) {
      await Promise.race(executing);
      executing.splice(
        executing.findIndex(e => e === p),
        1
      );
    }
  }

  return Promise.all(executing);
}

5️⃣ 合并请求

TypeScript
/**
 * 通知服务端合并分片
 */
function mergeChunks(hash: string, fileName: string) {
  return fetch('/upload/merge', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ hash, fileName }),
  });
}

六、服务端核心实现(Node.js 示例)

1️⃣ 接收分片

TypeScript
/**
 * 接收分片并保存到临时目录
 */
app.post('/upload/chunk', upload.single('chunk'), (req, res) => {
  const { hash, index } = req.body;
  const chunkDir = path.resolve(__dirname, 'temp', hash);

  if (!fs.existsSync(chunkDir)) {
    fs.mkdirSync(chunkDir, { recursive: true });
  }

  fs.renameSync(
    req.file.path,
    path.join(chunkDir, index)
  );

  res.json({ success: true });
});

2️⃣ 合并分片

TypeScript
/**
 * 合并所有分片
 */
app.post('/upload/merge', async (req, res) => {
  const { hash, fileName } = req.body;
  const chunkDir = path.resolve(__dirname, 'temp', hash);
  const filePath = path.resolve(__dirname, 'uploads', fileName);

  const chunks = fs.readdirSync(chunkDir).sort((a, b) => Number(a) - Number(b));
  const writeStream = fs.createWriteStream(filePath);

  for (const chunk of chunks) {
    const chunkPath = path.join(chunkDir, chunk);
    writeStream.write(fs.readFileSync(chunkPath));
    fs.unlinkSync(chunkPath);
  }

  writeStream.end();
  fs.rmdirSync(chunkDir);

  res.json({ success: true });
});

七、断点续传与秒传如何实现?

关键接口:查询已上传分片

TypeScript
GET /upload/status?hash=xxx

返回:

JSON
{
  "uploadedChunks": [0,1,2,5,6]
}

前端只上传 缺失的分片,即可实现:

  • 断点续传
  • 页面刷新继续
  • 网络失败恢复

八、最佳实践总结(非常重要)

前端最佳实践

  • 分片大小:2MB ~ 10MB
  • 并发数:3 ~ 6
  • hash 计算使用 Web Worker
  • 上传失败要支持重试
  • 显示真实进度(已完成分片 / 总分片)

后端最佳实践

  • 分片目录按 hash 隔离
  • 合并采用流式写入
  • 合并完成立即清理临时文件
  • 对合并接口加锁,防止重复合并
  • 支持幂等处理

九、总结

大文件分片上传并不是一个“技巧”,而是一个系统性工程问题:

  • 前端:性能、并发、稳定性、体验
  • 后端:可靠性、幂等性、资源控制
  • 架构:可恢复、可扩展、可维护

一套设计良好的分片上传方案,能够将 GB 级文件上传成功率提升到接近 100%,并显著改善用户体验。

标签: 分片上传 大文件上传 并发上传 断点续传
最后更新:2026年1月12日

cywcd

我始终相信,技术不仅是解决问题的工具,更是推动思维进化和创造价值的方式。从研发到架构,追求极致效能;在随笔中沉淀思考,于 AI 中对话未来。

打赏 点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

cywcd

我始终相信,技术不仅是解决问题的工具,更是推动思维进化和创造价值的方式。从研发到架构,追求极致效能;在随笔中沉淀思考,于 AI 中对话未来。

最新 热点 随机
最新 热点 随机
狂揽 32 万 Star,让 AI 智能体帮你“逆向一切”:深度拆解 GitHub 现象级神器 morluto/rea 与 6 大最佳实践 OpenCode 曝 1.4% 用户密钥失窃,揭秘黑客“对抗性蒸馏”黑产! Claude 全面开放 OTel 追踪、Cohere 鲸吞 500 漏洞猎手:AI 智能体彻底告别“黑盒裸奔”! 不用显卡、普通 CPU 140 毫秒出结果!Mistral 突发开源 209M 时序模型 Timestral,横扫三大权威榜单 Meta Muse 被“开源复刻”?深度拆解 5000 星 OpenMuse:架构很香,但这 3 个暗坑必须看清 智谱 GLM-Legal 反超 Claude 与 Kimi:18B 激活参数凭什么啃下最严苛法律评测?
不讲废话的 AI 估值 2 亿美元!全面拆解“系统一”决策模型 Jev:70ms 极速响应与工业级实战白嫖 10 亿 Token 与云端虚拟机!Meta Muse 国内成功注册保姆级指南:手把手教你跳过排队请3天休13天!我用火山引擎 Seed-2.1-pro搓了个《国庆旅行模拟器》小游戏宿敌破天荒联手!OpenAI 与 Anthropic 互相“查水表”,Google 证实 Agent 越狱渗透:AI 正在失控边缘?波及 13.4 万智能体!首个零点击 RCE 漏洞 Plugin4Shell 爆发:你锁定的插件正在偷偷黑掉你的电脑阿里开源 OpenCodeReview:给大模型套上“工程缰绳”的代码审查神器
第三方 Skill 成了大漏勺?拆解 Wake Forest 大学 Agent 凭证泄漏研究与沙箱隔离防线 🔥 狂揽 51.5k Star!这款名为 GSD 的神器,专治 AI 写代码"越写幻觉越严重" display:inline|block|inline-block的区别及特点 Workbox:可直接用于生产环境的 Service Worker 利器 别再把私人邮箱喂给AI了!解析QQ邮箱Agent Mail:专为智能体打造的“数字工位” Gemma 4发布4天即遭"完全越狱",开源AI的安全与自由之争
最近评论
cywcd 发布于 4 周前(09月22日) 《牛来跑酷》游戏链接地址已更新: 1. Gemini 3.7 Flash 版 牛来跑酷: htt...
渔夫 发布于 12 个月前(11月05日) 学到了,感谢博主分享
沙拉小王子 发布于 9 年前(11月30日) 适合vue入门者学习,赞一个
沙拉小王子 发布于 9 年前(11月30日) 适合vue入门者学习,赞一个
cywcd 发布于 10 年前(04月27日) 请参考一下这篇文章http://www.jianshu.com/p/fa4460e75cd8

COPYRIGHT © 2025 蓝戒博客_智构苍穹-专注于大前端领域技术生态. ALL RIGHTS RESERVED.

京ICP备12026697号-2