当前位置: 首页 > 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.dtcms.com/a/327379.html

相关文章:

  • 从零部署Nacos:替代Eureka的服务注册与服务发现基础教程
  • 视频输入输出模块介绍和示例
  • Dubbo 3.x源码(33)—Dubbo Consumer接收服务调用响应
  • Python day42
  • tensorrt-llm0.20.0离线部署DeepSeek-R1-Distill-Qwen-32B
  • 第六十三章:AI模型的“跨界之旅”:不同硬件架构下的兼容性方案
  • Linux NAPI 实现机制深度解析
  • 【CDA 新一级】学习笔记第1篇:数据分析的时代背景
  • 【前端八股文面试题】【JavaScript篇7】什么是JavaScript的原型、原型链? 有什么特点
  • 【设计模式精解】Java实现责任链模式(职责链模式)优雅处理多级请求(概述,使用场景,优缺点,代码示例)
  • Rust:构造函数 new() 如何进行错误处理?
  • 信号(Signal)** 是一种进程间异步通信机制,用于通知进程发生发生了某种事件(如错误、用户中断等)
  • 疯狂星期四文案网第37天运营日记
  • Apache POI中通过WorkBook写入图片后出现导出PDF文件时在不同页重复写入该图片问题,如何在通过sheet获取绘图对象清除该图片
  • 通过限制对象的内存分配位置来实现特定的设计目标
  • 【数据结构入门】堆
  • powerbi本地报表发布到web,以得到分享链接
  • C99中的变长数组(VLA)
  • 什么是 Spring MVC?
  • 中扬立库与西门子深化技术协同 共绘智能仓储创新蓝图
  • clean install 和 clean package 的区别
  • JVM学习笔记-----图解方法执行流程
  • 百胜软件×华为云联合赋能,“超级国民品牌”海澜之家新零售加速前行
  • 【力扣494】目标和
  • 【软考中级网络工程师】知识点之 IP QoS 技术
  • JVM宝典
  • 面试八股之从Java到JVM层面深入解析ReentrantLock实现原理
  • 力扣top100(day01-05)--矩阵
  • 开放原子开源生态大会:麒麟信安加入openEuler社区AI联合工作组,聚焦操作系统开源实践与行业赋能
  • Linux下的软件编程——文件IO