大文件分片上传与断点续传技术详解
1. 为什么需要分片上传与续传大文件上传一直是前端开发中的痛点问题。我曾在实际项目中遇到过用户上传3GB视频文件时网络波动导致上传失败用户不得不重新开始的糟糕体验。传统单次上传方式存在几个致命缺陷网络稳定性问题大文件上传耗时较长网络波动或中断会导致整个上传失败服务器压力单次处理大文件会占用大量服务器内存和带宽用户体验差失败后需要从头开始无法保留已上传部分超时风险HTTP请求默认有超时限制大文件容易触发分片上传将大文件切割成多个小块如每片5MB分别上传到服务器。这种方案的优势在于容错性强即使某片上传失败只需重传该片段而非整个文件支持暂停续传记录已上传片段后续可从断点继续并行上传可同时上传多个分片提高速度进度可控能精确计算上传百分比2. 核心实现方案设计2.1 整体流程架构一个完整的分片上传系统需要前后端协同工作前端 1. 文件选择 → 2. 分片切割 → 3. 上传分片 → 4. 确认合并 后端 1. 接收分片 → 2. 临时存储 → 3. 校验完整性 → 4. 合并文件2.2 前端关键技术点2.2.1 文件分片处理使用File API的slice方法实现分片切割function createFileChunks(file, chunkSize 5 * 1024 * 1024) { const chunks [] let cur 0 while (cur file.size) { chunks.push({ chunk: file.slice(cur, cur chunkSize), filename: ${file.name}-${cur} }) cur chunkSize } return chunks }注意浏览器兼容性方面IE10支持File.slice()对于更老浏览器需要polyfill2.2.2 分片上传控制实现并发控制避免浏览器请求数过多async function uploadChunks(chunks, maxConcurrent 3) { const pool new Set() let uploadedCount 0 for (let i 0; i chunks.length; i) { const task uploadSingleChunk(chunks[i]) .then(() { pool.delete(task) uploadedCount updateProgress(uploadedCount / chunks.length) }) pool.add(task) if (pool.size maxConcurrent) { await Promise.race(pool) } } await Promise.all(pool) }2.2.3 断点续传实现关键是在本地存储已上传分片信息// 获取文件唯一标识 function getFileKey(file) { return ${file.name}-${file.size}-${file.lastModified} } // 保存上传记录 function saveProgress(fileKey, chunkIndex) { const progress JSON.parse(localStorage.getItem(fileKey) || {}) progress[chunkIndex] true localStorage.setItem(fileKey, JSON.stringify(progress)) } // 检查已上传分片 function checkUploaded(fileKey, totalChunks) { const progress JSON.parse(localStorage.getItem(fileKey) || {}) return Array(totalChunks).fill() .map((_, i) progress[i] || false) }3. 后端接口设计与实现3.1 必要API接口3.1.1 分片上传接口POST /upload/chunk 参数 - file: 分片数据 - chunkIndex: 当前分片序号 - totalChunks: 总分片数 - fileHash: 文件唯一标识3.1.2 合并接口POST /upload/merge 参数 - fileHash: 文件唯一标识 - filename: 原始文件名 - totalChunks: 总分片数3.2 分片存储策略建议采用临时目录最终合并的方式/tmp /{fileHash} /0.chunk /1.chunk ...合并时按序号读取所有分片并写入最终文件const mergeFiles async (fileHash, filename) { const chunkDir path.join(tmp, fileHash) const chunks await fs.readdir(chunkDir) chunks.sort((a, b) parseInt(a) - parseInt(b)) const writeStream fs.createWriteStream(path.join(uploads, filename)) for (const chunk of chunks) { const chunkPath path.join(chunkDir, chunk) writeStream.write(await fs.readFile(chunkPath)) } writeStream.end() await fs.rm(chunkDir, { recursive: true }) }4. 高级优化与实战技巧4.1 文件秒传优化通过计算文件hash实现秒传async function calculateHash(file) { return new Promise(resolve { const reader new FileReader() reader.onload e { const spark new SparkMD5.ArrayBuffer() spark.append(e.target.result) resolve(spark.end()) } reader.readAsArrayBuffer(file) }) } // 上传前先检查 async function checkFileExist(fileHash) { const res await fetch(/api/check?hash${fileHash}) return res.json() }4.2 分片大小选择策略分片大小需要权衡太小请求次数过多增加开销太大失去分片优势重传成本高推荐策略100MB以下文件5MB/片100MB-1GB10MB/片1GB以上20MB/片4.3 错误处理与重试机制实现智能重试策略async function uploadWithRetry(chunk, retries 3) { for (let i 0; i retries; i) { try { return await uploadSingleChunk(chunk) } catch (err) { if (i retries - 1) throw err await new Promise(r setTimeout(r, 1000 * (i 1))) } } }5. 完整实现示例5.1 前端核心代码class BigFileUploader { constructor(options) { this.chunkSize options.chunkSize || 5 * 1024 * 1024 this.maxConcurrent options.maxConcurrent || 3 this.onProgress options.onProgress || (() {}) } async upload(file) { const fileHash await calculateHash(file) const exist await checkFileExist(fileHash) if (exist) return this.onProgress(1) const chunks createFileChunks(file, this.chunkSize) const uploaded checkUploaded(fileHash, chunks.length) const tasks chunks .filter((_, i) !uploaded[i]) .map(chunk () this.uploadChunk(chunk, fileHash)) await parallelLimit(tasks, this.maxConcurrent) await this.merge(file, fileHash) } async uploadChunk(chunk, fileHash) { const formData new FormData() formData.append(chunk, chunk.chunk) formData.append(chunkIndex, chunk.index) formData.append(fileHash, fileHash) await axios.post(/upload/chunk, formData) saveProgress(fileHash, chunk.index) } }5.2 常见问题排查问题1分片上传后合并失败可能原因分片顺序错乱 → 确保后端按数字顺序合并分片丢失 → 增加MD5校验临时文件权限问题 → 检查服务器目录权限问题2进度显示不准确解决方案使用Web Worker计算hash避免UI阻塞分片大小保持一致便于计算考虑使用requestAnimationFrame更新UI问题3大文件hash计算慢优化方案抽样hash只计算文件头尾和中间部分Web Worker并行计算显示计算进度在实际项目中我遇到过用户上传10GB视频文件的需求。通过实现分片上传断点续传将失败率从35%降到了2%以下。关键是要处理好内存管理——大文件切片时要避免同时加载所有分片到内存应该采用流式处理。

相关新闻

Lynx Clay NativeView 契约实现详解:C++ 驱动的 Native View 生命周期、布局与子树快照

Lynx Clay NativeView 契约实现详解:C++ 驱动的 Native View 生命周期、布局与子树快照

Lynx Clay NativeView 契约实现详解:C 驱动的 Native View 生命周期、布局与子树快照 【免费下载链接】lynx Empower the Web community and invite more to build across platforms. 项目地址: https://gitcode.com/GitHub_Trending/lynx10/lynx 本文基于 L…

2026/9/15 23:56:14 阅读更多 →
Loop Engineering 实战:git worktrees 并行开发——先分房、再点火、拿全绿分支说话

Loop Engineering 实战:git worktrees 并行开发——先分房、再点火、拿全绿分支说话

摘要:五条回路挤一个工作区会怎样?本文实战 git worktrees 并行开发:给五份任务书各分一间 worktree 机房,把单回路外环参数化成回路单元并行点火,用收敛看板聚合五条回路的轮次与退出码,最后逐条收割全绿分支。实录 62 条用例五路并进:四条一轮收敛,一条撞上自相矛盾的…

2026/9/15 23:53:45 阅读更多 →
PrimeVue TreeTable 组件完全指南:分层数据表格的导入、交互、懒加载与主题定制

PrimeVue TreeTable 组件完全指南:分层数据表格的导入、交互、懒加载与主题定制

PrimeVue TreeTable 组件完全指南:分层数据表格的导入、交互、懒加载与主题定制 【免费下载链接】primevue Next Generation Vue UI Component Library 项目地址: https://gitcode.com/GitHub_Trending/pr/primevue TreeTable 是 PrimeVue 中用于以表格形式展…

2026/9/15 23:56:23 阅读更多 →

最新新闻

Python面向对象编程进阶:从类与对象到组合设计实战

Python面向对象编程进阶:从类与对象到组合设计实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 23:55:47 阅读更多 →
增强子:基因调控中的“暗物质”如何被一步步看见?

增强子:基因调控中的“暗物质”如何被一步步看见?

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 23:55:47 阅读更多 →
AI无代码获取抖音热榜全攻略:产品人自学数据采集实操

AI无代码获取抖音热榜全攻略:产品人自学数据采集实操

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 23:55:47 阅读更多 →
深入剖析Java Unsafe:从CAS到堆外内存的魔法与陷阱

深入剖析Java Unsafe:从CAS到堆外内存的魔法与陷阱

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 23:55:47 阅读更多 →
设备自描述:嵌入式调试的范式跃迁与轻量实现

设备自描述:嵌入式调试的范式跃迁与轻量实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 23:55:47 阅读更多 →
基于Abaqus的纤维增强复合材料横向拉伸RVE模拟与损伤分析

基于Abaqus的纤维增强复合材料横向拉伸RVE模拟与损伤分析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 23:54:47 阅读更多 →

日新闻

Java高级技术:从语言特性到性能优化全解析

Java高级技术:从语言特性到性能优化全解析

1. Java高级技术概述Java作为一门成熟的编程语言,经过二十多年的发展已经形成了完整的生态系统。在企业级应用开发、大数据处理、移动开发等领域,Java都占据着重要地位。掌握Java高级技术不仅意味着能够编写更高效的代码,更代表着开发者能够解…

2026/9/15 0:00:23 阅读更多 →
C#与Halcon结合的工业视觉处理实战指南

C#与Halcon结合的工业视觉处理实战指南

1. 项目概述:C#与Halcon强强联合的视觉处理利器这个基于C#和Halcon的视觉处理Demo项目,是我在工业质检领域摸爬滚打多年后提炼出的实战精华。它完美融合了C#的界面开发优势与Halcon强大的图像处理能力,就像给视觉工程师配上了一把瑞士军刀。项…

2026/9/15 0:00:23 阅读更多 →
32路工业串口服务器的硬核选型指南:确定性、鲁棒性与协议下沉

32路工业串口服务器的硬核选型指南:确定性、鲁棒性与协议下沉

1. 为什么“32路复合型”不是营销话术,而是工业现场真实痛点的硬解你有没有遇到过这样的场景:在某大型能源站的PLC机柜里,十几台不同年代、不同品牌的温控仪、电表、气体分析仪、阀门控制器,全靠RS-485总线挂在一根线上&#xff0…

2026/9/15 0:00:23 阅读更多 →

周新闻

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验 【免费下载链接】ai The AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and ag…

2026/9/15 12:27:42 阅读更多 →
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化 【免费下载链接】refine A React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility. 项目地址: https://gitcode.com/GitH…

2026/9/15 1:32:25 阅读更多 →
Flutter应用改名全指南:从Android到iOS的配置与工具实践

Flutter应用改名全指南:从Android到iOS的配置与工具实践

刚接一个外包项目时,甲方要求把工程里临时用的应用名改成正式产品名。我本来觉得“改名”这种小事,打开配置文件改一行不就完了?结果真动手才发现,Flutter项目里“应用名称”根本不是一处配置,而是一整套散落在 Androi…

2026/9/15 1:32:21 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/15 21:40:00 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/15 21:39:18 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/15 21:40:17 阅读更多 →