当前位置: 首页 > news >正文

4.7 GB 视频导致浏览器内存溢出(OOM)的解决方案

在线教育平台大文件视频上传解决方案

场景

我们要做一个讲师后台的课程视频批量上传功能
需求听起来很简单:一次拖 20 个 4K 视频,浏览器稳、速度快、断网可续传。

第一版我图省事,用了:

<input type="file" />

配合:

const formData = new FormData();
formData.append('file', file);
fetch('/upload', { method: 'POST', body: formData });

结果上线当天就爆了:

  • 讲师 A:上传一个 4.7 GB 的 .movChrome 直接内存溢出崩溃

  • 讲师 B:断网 3 分钟 → 重新上传进度条从 0% 开始,心态崩

  • 运营同事:疯狂 @ 前端,“是不是没做分片?”

于是,第二版我设计了三层防线,核心思路就是——把大文件切成小片,让浏览器分开调用。


第一层防线:分片 + 并发控制

思路:4 GB 文件切成一堆小块(比如每块 2 MB),同时上传 5 块,既不卡浏览器也不占满带宽。

// slice.js
const CHUNK_SIZE = 2 * 1024 * 1024; // 2 MB 一块export async function* sliceFile(file) {let cur = 0;while (cur < file.size) {yield file.slice(cur, cur + CHUNK_SIZE);cur += CHUNK_SIZE;}
}
// uploader.js
import pLimit from 'p-limit';
import { sliceFile } from './slice.js';export async function upload(file) {const limit = pLimit(5);              // 同时最多 5 个请求const hash = await calcHash(file);    // 用于秒传 + 断点续传const tasks = [];for await (const chunk of sliceFile(file)) {tasks.push(limit(() => uploadChunk({ hash, chunk })));}await Promise.all(tasks);await mergeChunks(hash, file.name);   // 通知后端合并
}

📌 好处:

  1. file.slice 原生 API,不占额外内存

  2. p-limit 控制并发,避免一次性发出几百个请求打爆浏览器

  3. calcHash 用 WebWorker 算 MD5,不会卡 UI


第二层防线:断点续传

断点续传要解决的关键问题:续在哪?

我们需要一个“进度表”,记录哪些分片已经上传。

存储位置内容生命周期
前端 IndexedDBhash → 已上传分片索引数组本地有效,清缓存失效
后端 Redis/MySQLhash → 已接收分片索引数组可设置 TTL,支持跨设备续传

交互流程:

sequenceDiagramparticipant F as 前端participant B as 后端F->>B: POST /prepare {hash, totalChunks}B-->>F: 200 OK {uploaded: [0,3,7]}loop 上传剩余分片F->>B: POST /upload {hash, index, chunkData}B-->>F: 200 OKendF->>B: POST /merge {hash}B-->>F: 200 OK

第三层防线:协议可插拔

上传逻辑抽象成一个统一接口:

interface Uploader {prepare(file: File): Promise<PrepareResp>;upload(chunk: Blob, index: number): Promise<void>;merge(): Promise<string>;  // 返回文件 URL
}

这样我们可以快速切换:

  • BrowserUploader → 纯前端分片上传

  • TusUploader → tus.io 协议,天然断点续传

  • AliOssUploader → 直传阿里 OSS,利用 SDK 自带的断点续传

方案并发控制断点续传秒传代码量
自研手动实现自己实现手动300 行
tus内置协议级需后端100 行
OSS内置SDK 级自动50 行

加强功能

1. 秒传(Instant Upload)

先算 hash → 调 /exists?hash=xxx → 如果已存在,直接返回 URL,不走上传流程。

2. 加密上传

uploadChunk 前用 AES-GCM 加密数据块,后端存加密内容,下载时前端解密。

3. P2P 协同上传

用 WebRTC 让同一局域网的浏览器互传分片,然后统一上报,节省出口带宽。


小结

大文件上传的核心不是“传”,而是“断”。

  • 把大文件切成 2 MB 小块

  • 记住哪些块已经上传

  • 支持灵活切换上传协议

这样,浏览器就能稳稳地“吃下”任何体积的视频,哪怕是 4 GB 以上的大文件。

http://www.lryc.cn/news/618204.html

相关文章:

  • 小程序排名优化:功能迭代如何助力排名攀升
  • Python 爬虫获取淘宝商品信息、价格及主图的实战指南
  • 小程序排名优化:用户行为数据背后的提升密码
  • 从爬虫新手到DrissionPage实践者的技术旅程
  • Apache Shiro
  • Elasticsearch JavaScript 客户端「基础配置」全指南(Node/TS)
  • 7 种最佳 DBAN 替代方案,彻底擦除硬盘数据
  • ChatGpt 5系列文章1——编码与智能体
  • Go语言实战案例:使用模板渲染HTML页面
  • Go之封装Http请求和日志
  • mysql登录失败 ERROR1698
  • Elasticsearch Node.js 客户端连接指南(Connecting)
  • 实现一个二维码让 iOS 和 Android 用户自动跳转到对应下载链接
  • java面试题储备4: 谈谈对es的理解
  • 基于跨平台的svg组件编写一个svg编辑器
  • 【狂热算法篇】探寻图论幽径之SPFA算法:图论迷宫里的闪电寻径者(通俗易懂版)
  • 【门诊进销存出入库管理系统】佳易王医疗器械零售进销存软件:门诊进销存怎么操作?系统实操教程 #医药系统进销存
  • 需求分发机制如何设定
  • 飞算 JavaAI 电商零售场景实践:从订单峰值到供应链协同的全链路技术革新
  • 元器件--自恢复保险丝
  • 疏老师-python训练营-Day43复习日
  • 基于大数据的在线教育评估系统 Python+Django+Vue.js
  • 【代码随想录day 18】 力扣 501.二叉搜索树中的众数
  • 我的 LeetCode 日记:Day 35 - 解构动态规划,初探 0/1 背包问题
  • 如何检查pip版本
  • Spring Boot项目中调用第三方接口
  • 【Unity】GraphicRaycaster点击失效问题
  • 邦纳BANNER相机视觉加镜头PresencePLUSP4 RICOH FL-CC2514-2M工业相机
  • 一周学会Matplotlib3 Python 数据可视化-绘制饼状图(Pie)
  • 【Activiti】要点初探