96SEO 2026-09-15 22:31 11
这篇文章会用一个完整的前后端项目,带你从头理解“大文件上传”到底是怎么实现的。
项目使用 React + Vite 做前端,Node.js 原生 HTTP 模块做后端。前端负责选择文件、切片、计算 hash、上传分片、显示进度、暂停继续和失败重试;后端负责判断是否秒传、记录已经上传的分片、流式保存分片、合并文件和返回文件列表。

如果你是初学者,不用担心这套东西看起来名词很多。我们会从最朴素的问题开始讲:为什么普通上传不适合大文件?为什么要切片,为什么要 hash?按理说,为什么能断点续传?后端为什么不能直接把所有数据读到内存里?一步一步拆开之后你会发现大文件上传并不是魔法,而是一组很朴素的工程动作。不过,
User Pain Point: 使用者往往只看到一个单一进度条,却不知道到底是网络卡住还是服务器忙碌,导致失望与焦虑。
我们先想一个最简单的上传方式。使用者选择一个文件,前端把整个文件塞进 提交给后端:
const formData = new FormData;formData.append;await fetch,
如果文件只有几十 KB 或几 MB,这样做当然没问题。很多头像上传、图片上传、普通表单附件都是这么做。
当文件变成 GB 时问题就开始出现了:
大文件上传主要不是“怎么把一个文件传上去”,而是解决一系列工程问题:
- 上传失败后不要从头再传;使用者暂停可以继续,页面刷新也能找回已完成部分;同一份内容已存在时可秒传;前端能显示真实进度,后端能稳定处理大文件,不轻易占满内存。这就是我们为何要做“分片上传”。想象一下搬箱子——拆成小箱子比一次搬巨箱安全得多。
User Pain Point: 传统单次提交让人感觉“一次性操作”。但在真实网络环境下常常卡死或崩溃,让开发者抓狂。
主要思路可以一句话概括:
"前端把大文件切成很多小分片。一一或并发地发送给后端,后端逐个保存这些分片,并在全部齐全时按顺序合并成原始文件。"
但真正好用还需要补几个关键能力:
痛点 :每次手动重新 Upload 都浪费时间且易错——通过预查询减少重复工作。
“任务队列 + worker 函数”模式不断拉取 pendingQueue 中 nextChunk 且 await uploadChunkWithRetry。
pauseUpload 把 pausedRef=true 并 xhr.abort 所有正在请求。
resumeUpload 查询 status,只补齐缺失 block。
MAXRETRYCOUNT=6。每次失败延迟指数退避,直至达到上限才 mark failed。说起来,
痛点 :网络波动频繁导致大量重连—退避机制平衡速度与稳定性。
| 方法 | 方法 | 作用 |
|---|---|---|
| GET | /api/health | |
| GET | /api/upload/status | |
| POST | /api/upload/chunk | |
| POST | /api/upload/merge | |
| GET | /api/files |
js
const existingFile = await getMergedFile;if{sendJson}
else{
const uploadedChunks = await listUploadedChunks;
sendJson,}
js
import busboy from 'busboy';export function readMultipartChunk{
return new Promise=>{
const fields={};const bb=new busboy({
headers:req.headers。limits:{files:1,fileSize:1024*1024*200},});bb.on=>fields=val);bb.on=>{
if{stream.resume;return,}
onChunk;}),req.pipe;})
}
server/storage/
├─chunks/
│ └─
同一份内容无论命名为何,都落到同一目录 => 避免重复存储。其实,
.tmp 写临时再 rename 防止半成品留存。
``js
for{
if) missing.push;}
if throw {msg:${missing.length} 个缺失`,statusCode:400};
const tempPath=${finalPath}.tmp;const out=createWriteStream;// 顺序读取 .part 写入 out,end:false 防止 auto close。// 完整写完 -> rename
await rename;
js
const merging=new Set;if) throw {msg:'正在合併中...',statusCode:409};merging.add,// ...after merge finished remove from set...
ts type UploadPhase ='idle'|'hashing'|'checking'|'uploading'|'paused'|'merging'|'done'|'error';type ChunkStatus ='pending'|'uploading'|'success'|'retrying'|'failed'|'skipped';
每个阶段对应 UI 提示,如 hashing 显示 “计算哈希…”,error 显示错误信息。
1️⃣ 选择 → File 对象 & 初始化 ChunkItem 列表 若 file.size =100MB 且 CHUNK_SIZE=10MB,则创建10 个 Pending
2️⃣ 开始 → phase=hashing → WebWorker 开始计 MD5
- 显示 “计算哈希 …” 百帧更新
✅ 完成 ⇒ 得到 eaf61ae66c4fb863053f0b892abb258c
⚙️ 查询 /api/upload/status?fileHash=eaf61...
📦 响应 若未存在且没有任何 .part => shouldUpload:true
⚙️ 逐块 Upload via XHR ➜ 实时更新每 Block 与总 Progress
🤝 暂停 ➜ abort 所有 XHR,保留已成功 .part
🚀 继续 ➜
/status 检查缺失 Block。仅补齐其余
🔄 重试 如某 Block 超时 -> 自动 retry up to MAXRETRYCOUNT
🛠️ Merge 请求 /api/upload/merge -> Backend 检查齐全 -> 写 .tmp ➜ rename 成最终 file 🎉
📋 最终页面刷新 -> 展示 “已完成” 与下载链接
| 问题 | 痛点 | 解答 |
|---|---|---|
| 为什么不能仅靠名称判断? | 名称易变导致误判 | 用内容 Hash 更稳妥 |
| MD5 会冲突吗? | 理论上可能,但概率极低 | 常规业务足够安全。可选 SHA 系列 |
| 为什么放 WebWorker 算哈希? | 主线程卡顿导致 UI 无响应 | 背景线程保持界面流畅 |
| 为何不用 fetch 上报进度? | fetch 无 onprogress 支持 | XHR 提供精细控制 |
| 为什么使用 Busboy 而非标准解析器? | 标准解析一次性读完内存巨大 | Busboy 能流式处理降低峰值内存 |
| 暂停之后还能恢复吗? | 已成功 .part 保持在服务侧 | 下一轮 status 查询即可恢复 |
| 页面刷新的恢复能力有限怎么办? | 浏览器不允许持久 File 对象 | 可将最近一次记录保存在 localStorage。仅提示检测续签 |
1️⃣ 引入 User/Auth,以区分不同使用者的数据权限。2️⃣ 将 metadata 存于数据库而非 JSON 文件,以便更高效查询。3️⃣ 清理过期 .part 临时目录以节省硬盘空间。4️⃣ 将最终 file 放至对象存储 S3/Oss/Cos,只留签名与元数据。5️⃣ Redis 或 DB 锁替代内存 Set,支持多实例部署。6️⃣ 并发率,根据实际网络状况自适配。7️⃣ 支持 SHA‑256 或 SHA‑512,以兼顾安全需求。8️⃣ 多任务队列支持同时管理多个 File 的 Upload Flow。9️⃣ 支持目录递归压缩批量导入。🔟 自动回滚缺失 Block 并提醒使用者手动修复错误情况。
User Pain Points 汇总:
A solution that solves all:
.tmp 再 rename 保证完整;只记住这个链路:
选择→切割→算 Hash→查询→送缺失→合併→完成!
这样就能清晰讲解“大 文件 上传”的全部技术细节。也能快速定位遇到的问题所在——无论是 UX 卡顿还是服务器崩溃,都有对应方法!
祝你玩转大型附件!🚀
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback