news 2026/9/5 2:26:48

一文搞懂“流式数据分片上传“

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
一文搞懂“流式数据分片上传“

用户上传一段 2GB 的视频,结果上传到一半断了,用户急得骂人。有没有一种方案,能让大文件上传变得"断不断都不怕"。今天就把我研究出来的分片上传方案写下来,顺便把代码也贴出来,大家可以直接拿去用。


一、先搞懂一个问题:为什么要分片上传?

你有没有遇到过这种场景:

  • 上传一个 500MB 的视频,传到 99% 的时候网络抖动了一下,然后从头再来
  • 用户心态直接崩了。

传统上传方式就是把整个文件一次性发到服务器,简单粗暴,但有个致命缺陷:一旦中断,前功尽弃

分片上传的思路其实很简单——把大文件切成小块,一块一块传。这样即使某一块传失败了,只需要重传那一块,不用整个文件重来。

打个比方:

你要搬家,东西很多。传统方式是一辆卡车把所有家具一次拉走,路上抛锚了全部得重来。分片上传呢?叫了 10 辆小货车,每辆拉几件家具,哪辆抛锚了只修那辆,不影响其他的。


二、分片上传的完整流程

整个流程可以拆成 5 步,我尽量用大白话讲:

第 1 步:文件分片

把用户选中的大文件,按固定大小切成小块。比如每块 5MB,一个 50MB 的文件就切成 10 块。

前端用File.prototype.slice()方法就能切,不需要后端配合。

第 2 步:创建上传任务

在开始传之前,先跟服务器打个招呼:“我要传一个文件,请给我一个唯一的 uploadId”。这个 ID 就像快递单号,后面所有分片都要带上它,服务器靠它知道这些分片属于哪个文件。

第 3 步:并行上传分片

10 块分片不需要一块一块等,可以同时发起多个请求一起传。现代浏览器对同一个域名的并发连接数限制一般是 6 个,所以一次并发传 6 个分片,剩下的等前面的完了再继续。

第 4 步:服务端合并

所有分片都传完了,服务器收到通知,按分片序号把它们拼回去,就还原成了原始文件。

第 5 步:通知 AI 处理

文件合并完之后,如果业务需要(比如视频分析),再调用 AI 处理接口让它干活。


三、关键特性:让上传"抗造"的五个技能

光能传还不行,实际项目中用户的行为是不可控的。以下五个特性是必须支持的:

1. 断点续传

用户传着传着关了页面,下次再来打开,已经传完的分片不用重传,直接从断掉的地方继续。实现方式:每次传完一个分片,就把这个分片的序号存到 localStorage 里。重新上传时先查一下哪些传过了,跳过就行。

2. 并行上传

前面说了,同时发多个请求,速度起飞。但也不能无脑并发,浏览器有并发限制,一般设 3~6 个比较合理。

3. 进度显示

用户需要知道"到底传到哪了"。进度 = 已上传分片数 / 总分片数 × 100%。每传完一块就更新一下,用户体验拉满。

4. 错误重试

网络波动导致某个分片传失败了,不要直接报错停止,自动重试几次(比如 3 次),还是失败再告诉用户。

5. 暂停 / 恢复

用户可能突然不想传了,想暂停,等会儿再传。这个需要配合AbortController来实现取消请求。


四、前端代码实现

下面我把完整的分片上传类写出来,带注释,直接复制就能用(当然后端接口需要你自己配合)。

4.1 基础版:最简单的分片上传

先写一个最基础的版本,让你理解核心逻辑:

classChunkedUploader{constructor(options={}){this.chunkSize=options.chunkSize||5*1024*1024;// 每块 5MBthis.maxConcurrent=options.maxConcurrent||3;// 最大并发数this.retryCount=options.retryCount||3;// 重试次数this.onProgress=options.onProgress||(()=>{});// 进度回调}asyncupload(file,uploadId){consttotalChunks=Math.ceil(file.size/this.chunkSize);console.log(\`总共 \${totalChunks}个分片\`);// 记录每个分片的上传状态constchunkStatus=newArray(totalChunks).fill('pending');// 按批次并发上传for(leti=0;i<totalChunks;i+=this.maxConcurrent){constbatch=[];for(letj=0;j<this.maxConcurrent&&(i+j)<totalChunks;j++){constindex=i+j;conststart=index*this.chunkSize;constend=Math.min(start+this.chunkSize,file.size);constchunk=file.slice(start,end);batch.push(this._uploadChunk(uploadId,chunk,index).then(()=>{chunkStatus[index]='done';this.onProgress((index+1)/totalChunks*100);}));}awaitPromise.all(batch);}console.log('所有分片上传完成');}async_uploadChunk(uploadId,chunk,index){letretries=0;while
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 2:23:19

第二学期——数组、二分查找

数据结构与数组基础&#xff08;概念篇&#xff09; 栈、队列、树等。数组&#xff08;Array&#xff09;&#xff1a;特点&#xff1a;存储在连续内存空间&#xff0c;通过索引&#xff08;下标&#xff09;访问&#xff0c;时间复杂度 O(1)。优缺点&#xff1a;查找快&…

作者头像 李华
网站建设 2026/9/5 2:16:49

OpenCode Go:新一代 AI 编程助手的实战指南

1. 引言随着 AI 编程工具的快速发展&#xff0c;开发者对代码生成、自动补全和智能重构的需求越来越高。OpenCode Go 作为一款新兴的 AI 编程助手&#xff0c;凭借其强大的代码理解能力和灵活的配置方式&#xff0c;正在受到越来越多开发者的关注。本文将从安装配置、核心功能到…

作者头像 李华
网站建设 2026/9/5 2:15:55

涅槃乐队风格翻唱:从录音到母带的完整音乐制作技术解析

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

作者头像 李华
网站建设 2026/9/5 2:15:49

结构化与隔离:构建健壮数据处理管道的核心工程实践

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

作者头像 李华
网站建设 2026/9/5 2:15:40

Flutter OHOS 渲染引擎与UI相关问题

渲染引擎切换指导 PlatformView 同层渲染方案适配切换指导 flutter inappwebview 设置高度后网页内容被拉伸 问题分析&#xff1a;目前 OS 原生 web 画布限制范围是在 2400 以下&#xff0c;超过 2400 的高度原生 web 无法加载 解决方案&#xff1a;将 px 类型的参数转换为 …

作者头像 李华
网站建设 2026/9/5 2:15:37

AI网关实战:从模型路由到Agent协作的统一接入层

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

作者头像 李华