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

WebUploader+PHP如何实现大文件分片上传的断点续传方案?

咱福州网工仔实锤了!最近为了毕设焦头烂额——要搞个能打的大文件管理系统,还要兼容IE8这种“上古浏览器”(学校机房那台Win7+IE9的老古董,点个按钮都像在玩心跳)。找了一圈后端教程,不是“自己悟”就是“付费课”,现在连后端代码都要自己摸着石头过河……今天先把前端代码整明白,至少毕设演示时能“表面光”!


前端目标:用原生JS+WebUploader,搞定10G上传+断点续传+文件夹

咱一个后端小白,后端Python还在啃《笨办法学Python》,所以前端必须“能跑能用”——核心就三点:

  1. 兼容老浏览器:IE8用Flash,IE9+用H5,龙芯/红莲花这些信创浏览器也能跑。
  2. 断点续传:关浏览器/重启电脑都不怕,进度信息存本地(localStorage)。
  3. 文件夹上传:保留层级结构(比如/课程设计/文件管理系统/代码),IE8手动输路径凑合用。

前端代码:Vue3 + WebUploader(附详细注释)

先上干货!以下是核心代码,包含文件选择、分片上传、断点查询、文件夹处理,注释写得贼详细,小白也能看懂。

1. 安装依赖(VS Code里操作)

首先得装WebUploader和加密库(AES加密用):

# 在项目根目录敲命令(Vue3用npm或yarn都行)npminstallwebuploader crypto-js --save
2. 前端组件代码(src/components/BigFileUpload.vue)
import SparkMD5 from 'spark-md5'; // 计算文件MD5(断点续传关键) import WebUploader from 'webuploader'; // 引入WebUploader库 import CryptoJS from 'crypto-js'; // AES加密库(传输加密) export default { data() { return { uploader: null, // WebUploader实例 progress: 0, // 上传进度百分比 isUploading: false, // 是否正在上传 currentFile: null, // 当前处理的文件 fileMd5: '', // 当前文件的MD5(唯一标识,用于断点) chunkSize: 2 * 1024 * 1024, // 分片大小2MB(10G分5000片) uploadedChunks: [], // 已上传的分片序号(从本地localStorage读) encryptKey: 'user-defined-key-123' // 加密密钥(实际项目要让用户输入!) }; }, mounted() { this.initUploader(); // 初始化上传组件 }, methods: { // 初始化WebUploader(兼容IE8的Flash模式) initUploader() { // 配置WebUploader(重点参数注释) this.uploader = WebUploader.create({ swf: '/static/webuploader/Uploader.swf', // Flash路径(IE8必须,需提前下载) server: '/api/upload/chunk', // 后端分片接收接口(Python写的,后面说) pick: '#filePicker', // 选择文件按钮 dnd: '#dndArea', // 拖拽区域 paste: document.body, // 粘贴上传(可选) chunked: true, // 开启分片上传(大文件必须) chunkSize: this.chunkSize, // 分片大小2MB compress: false, // 不压缩(大文件压缩会丢内容) fileNumLimit: 100, // 最多同时传100个文件(防崩溃) fileSizeLimit: 10 * 1024 * 1024 * 1024, // 单个文件最大10G accept: { title: 'All Files', extensions: '*' // 允许所有格式(按需改) }, // 自定义参数(传给后端) formData: { encrypt: 'true', // 告诉后端要加密传输 key: this.encryptKey // 加密密钥(实际让用户输入更安全) } }); // 绑定事件:文件加入队列时触发(计算MD5) this.uploader.on('fileQueued', (file) => { this.currentFile = file; this.progress = 0; this.uploadedChunks = []; // 重置已上传分片 this.calculateFileMd5(file); // 计算文件MD5(断点续传的核心) }); // 绑定事件:分片上传前(查询已上传的分片) this.uploader.on('uploadBeforeSend', (obj, data) => { data.md5 = this.fileMd5; // 传MD5给后端查进度 data.chunk = obj.chunk; // 当前分片序号(0开始) data.chunks = obj.chunks; // 总分片数 }); // 绑定事件:上传进度更新(实时显示进度条) this.uploader.on('uploadProgress', (file, percentage) => { this.progress = Math.round(percentage * 100); }); // 绑定事件:单个分片上传成功(记录已上传分片到localStorage) this.uploader.on('uploadSuccess', (file, response) => { if (response.code === 200) { const { chunk } = response.data; this.uploadedChunks.push(chunk); // 记录已上传的分片序号 localStorage.setItem(`upload_${this.fileMd5}`, JSON.stringify(this.uploadedChunks)); // 存本地防丢失 } }); // 绑定事件:全部分片上传完成(合并文件) this.uploader.on('uploadFinished', (file) => { this.isUploading = false; this.$message.success(`${file.name} 上传完成!`); // 清空本地存储的进度(可选) localStorage.removeItem(`upload_${this.fileMd5}`); }); // 绑定事件:上传出错(提示用户) this.uploader.on('error', (type) => { this.isUploading = false; let msg = ''; switch (type) { case 'F_EXCEED_SIZE': msg = '文件超过10G限制!'; break; case 'Q_EXCEED_NUM_LIMIT': msg = '同时上传的文件太多!'; break; default: msg = `上传失败:${type}`; } this.$message.error(msg); }); }, // 计算文件MD5(断点续传的唯一标识) calculateFileMd5(file) { const blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice; const chunks = Math.ceil(file.size / this.chunkSize); // 总分片数 const spark = new SparkMD5.ArrayBuffer(); const fileReader = new FileReader(); // 分片读取文件内容,计算MD5(大文件可能有点慢,耐心等) const loadNext = (currentChunk) => { const start = currentChunk * this.chunkSize; const end = Math.min(start + this.chunkSize, file.size); fileReader.readAsArrayBuffer(blobSlice.call(file, start, end)); }; fileReader.onload = (e) => { spark.append(e.target.result); // 累加当前分片内容 const currentChunk = Math.floor(e.target.result.byteLength / this.chunkSize); if (currentChunk < chunks - 1) { loadNext(currentChunk); } else { this.fileMd5 = spark.end(); // 所有分片读完,得到最终MD5 this.queryUploadedChunks(); // 查询后端已上传的分片 } }; loadNext(0); // 开始计算 }, // 查询后端已上传的分片(从localStorage或后端接口) async queryUploadedChunks() { try { // 先从localStorage找(防止关浏览器后进度丢失) const localChunks = localStorage.getItem(`upload_${this.fileMd5}`); if (localChunks) { this.uploadedChunks = JSON.parse(localChunks); } else { // 没本地记录,调后端接口查(Python接口返回已上传的分片序号) const res = await this.$http.get(`/api/upload/chunks?md5=${this.fileMd5}`); this.uploadedChunks = res.data.uploadedChunks || []; } // 告诉WebUploader跳过已上传的分片(关键!) this.uploader.options.chunkRetry = 0; // 失败不重试(已上传的分片跳过) this.uploader.upload(); // 开始上传 } catch (err) { console.error('查询已上传分片失败', err); this.$message.error('获取上传进度失败,请重试'); } }, // 开始上传 startUpload() { if (!this.currentFile) { this.$message.warning('请先选择文件或文件夹!'); return; } this.isUploading = true; this.uploader.upload(); }, // 暂停上传 pauseUpload() { this.uploader.stop(); this.isUploading = false; }, // 清空队列 clearQueue() { this.uploader.clearQueue(); this.progress = 0; this.currentFile = null; this.uploadedChunks = []; } } }; .upload-container { max-width: 800px; margin: 20px auto; padding: 20px; border: 1px solid #eee; border-radius: 8px; } .placeholder { min-height: 150px; border: 2px dashed #ccc; border-radius: 4px; display: flex; flex-direction: column; align-items: center; justify-content: center; cursor: pointer; } .tip { color: #666; font-size: 12px; margin-top: 10px; } .status-bar { margin-top: 15px; } .progress-wrap { margin-bottom: 15px; } .progress-bar { width: 100%; height: 20px; background: #f3f3f3; border-radius: 10px; overflow: hidden; margin: 5px 0; } .progress { height: 100%; background: #409eff; transition: width 0.3s; } .btn-group button { margin-right: 10px; padding: 5px 15px; border: 1px solid #ddd; border-radius: 4px; cursor: pointer; } .btn-group button:disabled { background: #f5f5f5; color: #999; cursor: not-allowed; }

代码关键功能说明(小白必看)

  1. 兼容IE8:靠WebUploader的Flash模式(swf文件),记得把Uploader.swf放在public/static/webuploader/目录下(Vue3默认静态资源路径)。
  2. 断点续传
    • 文件加入队列时,用SparkMD5计算文件的MD5(唯一标识)。
    • 上传前调用queryUploadedChunks,从本地localStorage或后端接口查已上传的分片。
    • WebUploader会自动跳过已上传的分片,只传未传的部分。
  3. 文件夹上传
    • IE9+支持webkitdirectory属性(WebUploader自动处理),拖拽文件夹时会保留层级结构(比如/课程设计/文件管理系统)。
    • IE8不支持,只能手动让用户输入文件夹路径(比如在文件名前加课程设计/前缀),后端按路径创建文件夹。
  4. 加密传输
    • 前端用CryptoJS.AES.encrypt加密文件内容(示例里没写,可加在uploadBeforeSend事件里)。
    • 后端用相同的密钥解密(Python代码里实现)。

毕设演示注意事项(保命指南)

  1. 本地测试
    • 用Win7虚拟机装IE9,测试文件夹上传和断点续传(上传到50%时关闭浏览器,重新打开继续传)。
    • 用IE8虚拟机测试Flash上传(需允许浏览器运行Flash,学校机房可能需要调整安全设置)。
  2. 进度保存
    • 关闭浏览器再打开,刷新页面,看进度是否还在(依赖localStorage)。
  3. 大文件测试
    • 用10G的测试文件(网上找“10G测试文件生成器”),看分片上传是否正常,有没有内存溢出。

求救!后端Python怎么搞?

我现在后端Python还在啃,大概思路是:

  • 用Flask或Django写接口,接收分片(/api/upload/chunk)。
  • 把分片存到本地临时目录(比如F:/temp_uploads/)。
  • uploadedChunks表(或本地文件记录),合并分片成完整文件。
  • 加密存储(用AES解密前端传过来的内容,再存到项目目录)。

有没有Python大佬愿意带带弟弟?加群374992201,新人有红包!群里还有一起学后端的兄弟,平时布置作业互相监督,毕设答辩前互相调试代码~

(PS:老师说“能跑起来就行”,但我争取做到“看起来很牛”——毕竟这是大学最后作业了,冲就完事了!)

将组件复制到项目中

示例中已经包含此目录

引入组件

配置接口地址

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

处理事件

启动测试

启动成功

效果

数据库

效果预览

文件上传

文件刷新续传

支持离线保存文件进度,在关闭浏览器,刷新浏览器后进行不丢失,仍然能够继续上传

文件夹上传

支持上传文件夹并保留层级结构,同样支持进度信息离线保存,刷新页面,关闭页面,重启系统不丢失上传进度。

下载示例

点击下载完整示例

http://www.jsqmd.com/news/420623/

相关文章:

  • 总结佛山吸塑工厂口碑排名,深圳市乙方吸塑包装排第几? - myqiye
  • 汽车制造企业如何用ASP.NET实现文件夹上传?
  • 【高企日报】谁需要《高企管理成熟度认证》?——一张图看清你的位置
  • 工程建筑领域ASP.NET应用如何分享文件夹上传方案?
  • 当AI生图突破速度边界:Nano Banana2+ChatPPT如何重塑视觉生产
  • PHP后端如何配合WebUploader实现超大附件秒传与断点续传?
  • 应对专利无效、权属纠纷,企业如何守住核心技术产权?
  • 芯片制造中,C#如何处理文件夹上传的加密需求?
  • 2026年目前有名的抖音广告代运营企业口碑推荐榜,抖音广告代运营/信息流广告代运营,抖音广告代运营公司推荐排行榜 - 品牌推荐师
  • 青岛口碑不错的隐形车衣专业公司费用怎么算 - mypinpai
  • 露,集成化信息化信号采集处理系统 一体化生物医学信号采集系统 机能集成化信号采集与处理系统
  • LeetCode1680:连接连续二进制数字
  • 以太网接口设备写静态路由的时候为什么写下一跳ip地址?而不是出接口。(ensp模拟说明)
  • 上海宠物口腔健康守护者:2026年优质医生推荐,狗口腔溃疡诊疗/狗狗牙结石/猫咪口腔护理/猫咪口炎,宠物口腔医生哪个靠谱 - 品牌推荐师
  • 哈尔滨沃尔沃XC90俄罗斯STP汽车隔音降噪 有效解决胎噪、风噪、发动机噪音 哈尔滨最专业汽车隔音店-博士达汽车音响倾心打造
  • 科研党收藏!降AI率平台 千笔·降AIGC助手 VS Checkjie,专为本科生定制
  • Snowflake收购数据库迁移技术初创公司Datometry
  • 闭眼入!8个AI论文网站深度测评:继续教育毕业论文写作必备工具推荐
  • 交稿前一晚!降AIGC平台 千笔·专业降AI率智能体 VS WPS AI,继续教育必备神器
  • 别再瞎找了!AI论文平台 千笔ai写作 VS 灵感ai,自考写论文就选它!
  • 6.4 企业数据分析师Agent:数据查询与报告生成实战
  • 6.3 智能客服系统端到端开发:对话管理加RAG加人工转接
  • 什么时候该用接口,什么时候该用抽象类,应该怎么组合才好用,才高级
  • 2026年2月实木家具实力厂家推荐榜,匠心工艺实测解析 - 品牌鉴赏师
  • 大模型不是你家熊孩子:聊聊生成式模型“去偏 / 去毒”流水线怎么落地
  • 想选专业的家装装修设计公司,上海朗域装饰的口碑咋样 - mypinpai
  • 2026年2月木工机械设备供应厂家推荐,资质案例售后深度解读 - 品牌鉴赏师
  • 大二寒假实习小结(嵌入式软件开发岗)
  • 别小看一个“偷看”:Peeking Iterator 背后的设计哲学
  • 001 nvm 管理不同版本的 node 与 npm