JS如何利用切片技术实现超大附件的秒传与续传?
大文件上传:必须分片,但IE9可能会原地爆炸文件夹结构:现代浏览器可用webkitRelativePath,IE9…放弃吧断点续传:localStorage存进度,但IE9只有5MB空间加密传输:crypto-js库可以,但会增大体积100元预算:建议买杯咖啡清醒一下。
前端老哥的奇幻漂流:20G文件上传历险记
大家好,我是那个"预算100元想造航天飞机"的陕西前端老哥。最近接了个外包,客户要求用原生JS实现20G文件上传,还要兼容IE9…我差点没把手中的肉夹馍吓掉!
需求分析(血压升高版)
客户要的功能清单:
- 20G文件上传(我电脑硬盘才256G啊!)
- 文件夹结构保持(1000+文件那种)
- 加密传输(SM4/AES)
- 断点续传(关机重启都不能丢进度)
- 兼容IE9(2011年的老古董了)
- 100元预算(还含3年维护)
这哪是外包需求,这分明是想用自行车价格买劳斯莱斯啊!不过老哥我混迹江湖多年,还是硬着头皮上了…
前端解决方案(穷得叮当响版)
// 文件上传核心代码 - 精简版(完整代码请加QQ群领取)
class MegaUploader {
constructor() {
this.chunkSize = 5 * 1024 * 1024; // 5MB分片(IE9会哭的)
this.maxRetry = 3; // 重试次数(心态要好)
this.queue = []; // 上传队列(希望不要爆内存)
this.supportFolder = !!window.FileSystem; // 检测文件夹支持(IE9:你在想peach)
}
// 加密函数(假装很安全)
encrypt(data, key, algo = 'AES') {
return `${algo}::${btoa(data)}::${key}`; // 真加密请用crypto-js
}
// 分片上传(祈祷不要蓝屏)
async uploadChunk(file, start, end, chunkIndex) {
const chunk = file.slice(start, end);
const encrypted = this.encrypt(chunk, '客户付不起加密钱');
return new Promise((resolve, reject) => {
let retry = 0;
const tryUpload = () => {
const xhr = new XMLHttpRequest();
xhr.open('POST', '/upload', true);
xhr.setRequestHeader('Content-Type', 'application/octet-stream');
xhr.setRequestHeader('X-Chunk-Index', chunkIndex);
xhr.onload = () => resolve(xhr.response);
xhr.onerror = () => ++retry < this.maxRetry ? tryUpload() : reject();
xhr.send(encrypted);
};
tryUpload();
});
}
// 处理文件夹上传(IE9用户请自觉退出)
async uploadFolder(folder) {
if (!this.supportFolder) {
alert('您的浏览器太古老,建议升级到本世纪版本');
return;
}
const entries = await this.readDirectory(folder);
for (const entry of entries) {
if (entry.isFile) {
await this.uploadFile(await entry.getFile());
} else if (entry.isDirectory) {
await this.uploadFolder(entry);
}
}
}
// 断点续传(全靠localStorage死撑)
saveProgress(fileId, progress) {
localStorage.setItem(`upload_${fileId}`, JSON.stringify(progress));
// 注意:IE9的localStorage只有5MB哦~
}
}
// 使用示例(希望客户不会看控制台)
const uploader = new MegaUploader();
document.getElementById('file-input').addEventListener('change', (e) => {
const file = e.target.files[0];
if (file.size > 20 * 1024 * 1024 * 1024) {
alert('老板,得加钱!20G文件太烧CPU了');
return;
}
uploader.uploadFile(file).catch(() => alert('上传失败,请检查网络或加预算'));
});
IE9兼容方案(玄学版)
// IE9专属polyfill(效果看天意)
if (navigator.userAgent.indexOf('MSIE 9') !== -1) {
console.log('检测到上古浏览器,开始施法...');
// 假装支持Promise
window.Promise = window.Promise || function(executor) {
executor(
value => setTimeout(() => this.onFulfilled(value), 0),
reason => setTimeout(() => this.onRejected(reason), 0)
);
};
// 假装支持File API
window.File = window.File || function() {};
window.FileReader = window.FileReader || function() {
this.readAsArrayBuffer = function() {
alert('IE9不支持大文件上传,建议换浏览器或加钱');
};
};
}
技术总结(心酸版)
- 大文件上传:必须分片,但IE9可能会原地爆炸
- 文件夹结构:现代浏览器可用webkitRelativePath,IE9…放弃吧
- 断点续传:localStorage存进度,但IE9只有5MB空间
- 加密传输:crypto-js库可以,但会增大体积
- 100元预算:建议买杯咖啡清醒一下
友情提示
老哥我最后想通了:这需求100元真做不了!不过欢迎加群374992201交流(真的有红包),我们可以:
- 一起吐槽奇葩客户
- 分享接单防坑指南
- 组团开发分(逃)担(跑)压力
记住:程序员要团结,别让低价外包毁了行业!💪
(完整代码因"预算不足"无法在此展示,请加群领取…开玩笑的,真要实现这么复杂的功能,建议预算后面加几个零)
将组件复制到项目中
示例中已经包含此目录
引入组件

配置接口地址
接口地址分别对应:文件初始化,文件数据上传,文件进度,文件上传完毕,文件删除,文件夹初始化,文件夹删除,文件列表
参考:http://www.ncmem.com/doc/view.aspx?id=e1f49f3e1d4742e19135e00bd41fa3de
处理事件

启动测试

启动成功

效果

数据库

效果预览
文件上传

文件刷新续传
支持离线保存文件进度,在关闭浏览器,刷新浏览器后进行不丢失,仍然能够继续上传
文件夹上传
支持上传文件夹并保留层级结构,同样支持进度信息离线保存,刷新页面,关闭页面,重启系统不丢失上传进度。
批量下载
支持文件批量下载
下载续传
文件下载支持离线保存进度信息,刷新页面,关闭页面,重启系统均不会丢失进度信息。
文件夹下载
支持下载文件夹,并保留层级结构,不打包,不占用服务器资源。
下载示例
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)