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

【VUE】前端阿里云OSS断点续传,分片上传

什么是OSS:

数据以对象(Object)的形式存储在OSS的存储空间(Bucket )中。如果要使用OSS存储数据,您需要先创建Bucket,并指定Bucket的地域、访问权限、存储类型等属性。创建Bucket后,您可以将数据以Object的形式上传到Bucket,并指定Object的文件名(Key)作为其唯一标识。

分片上传:

在上传大文件(超过5 GB)到OSS的过程中,如果出现网络中断、程序异常退出等问题导致文件上传失败,您需要使用分片上传的方式上传大文件。分片上传通过将待上传的大文件分成多个较小的碎片(Part),充分利用网络带宽和服务器资源并发上传多个Part,加快上传完成时间,并在Part上传完成之后调用CompleteMultipartUpload接口将这些Part组合成一个完整的Object。

断点续传上传:

在上传大文件(超过5 GB)到OSS的过程中,如果出现网络中断、程序异常退出等问题导致文件上传失败,甚至重试多次仍无法完成上传,您需要使用断点续传上传的方式。断点续传上传将需要上传的大文件分成多个较小的分片并发上传,加速上传完成时间。如果上传过程中,某一分片上传失败,再次上传时会从Checkpoint文件记录的断点继续上传,无需重新上传所有分片。上传完成后,所有分片将合并成完整的文件。

 一.验证服务端是否已有该文件、该文件是否已上传部分块?

点击上传文件→选择文件后→读取文件信息→计算MD5值→发送给服务器→查看服务器返回信息

 计算MD5:

import SparkMD5 from 'spark-md5';this.calculateMD5(files.raw, this.sliceSize).then(async (md5) => {console.log(md5)}).catch((error) => {this.$message.error(error);});// md5 计算calculateMD5(file, chunkSize) {return new Promise((resolve, reject) => {const chunks = Math.ceil(file.size / chunkSize);let currentChunk = 0;const spark = new SparkMD5.ArrayBuffer();const fileReader = new FileReader();fileReader.onload = (e) => {spark.append(e.target.result); // 更新 MD5 值currentChunk++;if (currentChunk < chunks) {this.loadNextChunk(fileReader, currentChunk, chunkSize, file);} else {const md5 = spark.end(); // 计算最终 MD5 值resolve(md5);}};fileReader.onerror = function (e) {reject(e);};this.loadNextChunk(fileReader, currentChunk, chunkSize, file);});},// md5 计算loadNextChunk(fileReader, currentChunk, chunkSize, file) {const start = currentChunk * chunkSize;const end = Math.min(start + chunkSize, file.size);const chunk = file.slice(start, end);fileReader.readAsArrayBuffer(chunk);},

二 文件切块

			sliceSize: 1024 * 1024 * 2, // 分片上传-每片5MBfileBlockArr: [],_this.fileBlockArr = [];let blob = file.raw;const { size: fileSize, name: fileName } = blob;//计算文件切片总数,Math.ceil向上取整const totalSlice = Math.ceil(fileSize / _this.sliceSize);_this.chunktotle = totalSlice;for (let i = 0; i < totalSlice; i++) {let start = i * _this.sliceSize;let end = Math.min(fileSize, start + _this.sliceSize);let chunkBlob = blob.slice(start, end); // 直接使用slice方法分片Blob对象_this.fileBlockArr.push(chunkBlob);}

三 调用初始化接口

调用初始化接口,拿到部分参数后进行块上传

						const requestList = [];_this.fileBlockArr.forEach((item, index) => {if (index + 1 >= sliceNo) {const fn = () => {let data = new FormData();data.append('file', item);data.append('fileSlicesNum', totalSlice);data.append('sliceNo', index + 1);data.append('fileMD5', md5);data.append('resourceKey', _this.resourceKey);data.append('ossSlicesId', _this.ossSlicesId);data.append('fileSize', fileSize);return axios({url: process.env.VUE_APP_BASE_API + '/common/partUpload',method: 'post',data: data,headers: {Authorization: 'Bearer ' + getToken(),'Content-Type': 'multipart/form-data',},}).then((res) => {if (res.data.code === 200) {if (_this.percentCount === 0) {// 避免上传成功后会删除切片改变 chunkList 的长度影响到 percentCount 的值_this.percentCount = 100 / _this.fileBlockArr.length;}// _this.percent += _this.percentCount; // 改变进度_this.percent = res.data.progressPercent;_this.fileBlockArr.splice(index, 1); // 一旦上传成功就删除这一个 chunk,方便断点续传}}).catch((err) => {return Promise.reject(err);});};requestList.push(fn);}});let i = 0; // 记录发送的请求个数

四 上传与合并

						let i = 0; // 记录发送的请求个数const complete = () => {let completedData = {ossSlicesId: _this.ossSlicesId,resourceKey: _this.resourceKey,fileMD5: _this.md5,};completePart(completedData).then((response) => {if (response.code == 200) {_this.form.versionUrl = response.data;}}).catch((error) => {console.log('completePart-error:', error);});};const send = async () => {if (i >= requestList.length) {complete();return;}await requestList[i]();i++;send();};send(); // 发送请求

全览

data(){return {sliceSize: 1024 * 1024 * 2, // 分片上传-每片5MBchunktotle: 0,percentCount: 0,percent: 0,md5: '',fileBlockArr: [],resourceKey: undefined,ossSlicesId: undefined,fileName: undefined,}},methods:{uploadChange(files, fileList) {this.fileName = files.name;this.calculateMD5(files.raw, this.sliceSize).then(async (md5) => {this.md5 = md5;// 分片验证let checkData = {fileMD5: this.md5,};continueUpload(checkData).then((response) => {if (response.code === 200) {if (response.data !== null &&response.data.sliceNo < response.data.fileSlicesNum) {//已存在,但未上传完成 取已上传到的块信息this.resourceKey = response.data.resourceKey;this.ossSlicesId = response.data.ossSlicesId;let sliceNo = response.data.sliceNo;blockUpload(files, sliceNo + 1);} else if (response.data !== null &&response.data.sliceNo == response.data.fileSlicesNum) {// 上传完成待合并let completedData = {ossSlicesId: response.data.ossSlicesId,resourceKey: response.data.resourceKey,fileMD5: _this.md5,};mergePart(completedData);} else {// 未上传partInit({fileName: files.name,storageDirectory: 'internalApp',}).then((response) => {if (response.code === 200) {this.resourceKey = response.data.resourceKey;this.ossSlicesId = response.data.ossSlicesId;blockUpload(files, 0);}});}}}).catch((error) => {console.log('continueUpload-error:', error);});function mergePart(completedData) {completePart(completedData).then((response) => {if (response.code == 200) {let fileData = {name: _this.fileName,url: response.data,};_this.fileList.push(fileData);_this.form.versionUrl = response.data;}}).catch((error) => {console.log('completePart-error:', error);});}let _this = this;function blockUpload(file, sliceNo) {_this.fileBlockArr = [];let blob = file.raw;const { size: fileSize, name: fileName } = blob;//计算文件切片总数,Math.ceil向上取整const totalSlice = Math.ceil(fileSize / _this.sliceSize);_this.chunktotle = totalSlice;for (let i = 0; i < totalSlice; i++) {let start = i * _this.sliceSize;let end = Math.min(fileSize, start + _this.sliceSize);let chunkBlob = blob.slice(start, end); // 直接使用slice方法分片Blob对象_this.fileBlockArr.push(chunkBlob);}const requestList = [];_this.fileBlockArr.forEach((item, index) => {if (index + 1 >= sliceNo) {const fn = () => {let data = new FormData();data.append('file', item);data.append('fileSlicesNum', totalSlice);data.append('sliceNo', index + 1);data.append('fileMD5', md5);data.append('resourceKey', _this.resourceKey);data.append('ossSlicesId', _this.ossSlicesId);data.append('fileSize', fileSize);return axios({url: process.env.VUE_APP_BASE_API + '/common/partUpload',method: 'post',data: data,headers: {Authorization: 'Bearer ' + getToken(),'Content-Type': 'multipart/form-data',},}).then((res) => {if (res.data.code === 200) {if (_this.percentCount === 0) {// 避免上传成功后会删除切片改变 chunkList 的长度影响到 percentCount 的值_this.percentCount = 100 / _this.fileBlockArr.length;}// _this.percent += _this.percentCount; // 改变进度_this.percent = res.data.progressPercent;_this.fileBlockArr.splice(index, 1); // 一旦上传成功就删除这一个 chunk,方便断点续传}}).catch((err) => {return Promise.reject(err);});};requestList.push(fn);}});let i = 0; // 记录发送的请求个数const complete = () => {let completedData = {ossSlicesId: _this.ossSlicesId,resourceKey: _this.resourceKey,fileMD5: _this.md5,};mergePart(completedData);};const send = async () => {if (i >= requestList.length) {complete();return;}await requestList[i]();i++;send();};send(); // 发送请求}}).catch((error) => {this.$message.error(error);});},// md5 计算calculateMD5(file, chunkSize) {return new Promise((resolve, reject) => {const chunks = Math.ceil(file.size / chunkSize);let currentChunk = 0;const spark = new SparkMD5.ArrayBuffer();const fileReader = new FileReader();fileReader.onload = (e) => {spark.append(e.target.result); // 更新 MD5 值currentChunk++;if (currentChunk < chunks) {this.loadNextChunk(fileReader, currentChunk, chunkSize, file);} else {const md5 = spark.end(); // 计算最终 MD5 值resolve(md5);}};fileReader.onerror = function (e) {reject(e);};this.loadNextChunk(fileReader, currentChunk, chunkSize, file);});},// md5 计算loadNextChunk(fileReader, currentChunk, chunkSize, file) {const start = currentChunk * chunkSize;const end = Math.min(start + chunkSize, file.size);const chunk = file.slice(start, end);fileReader.readAsArrayBuffer(chunk);},
}

相关文章:

【VUE】前端阿里云OSS断点续传,分片上传

什么是OSS&#xff1a; 数据以对象&#xff08;Object&#xff09;的形式存储在OSS的存储空间&#xff08;Bucket &#xff09;中。如果要使用OSS存储数据&#xff0c;您需要先创建Bucket&#xff0c;并指定Bucket的地域、访问权限、存储类型等属性。创建Bucket后&#xff0c;您…...

春招面试高频题目总结

面试问题 redis 可以用于进程间通信吗&#xff1f; Why&#xff1f;How? ---> 延展一下 有哪些进程间通信技术, 优劣如何&#xff1f; 有大量的插入sql语句&#xff0c;一条条的插入性能很差&#xff0c;如何通过事务进行优化&#xff1f; 保证线程安全的策略有哪些&…...

基于SSM+Jsp+Mysql的KTV点歌系统

基于SSMJspMysql的KTV点歌系统 基于SSMJspMysql的KTV点歌系统的设计与实现 开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工…...

Docker Oracle提示密码过期

进入docker docker exec -it oracle bash 修改环境变量文件 vi .bash_profile 为以下内容 # .bash_profile# Get the aliases and functions if [ -f ~/.bashrc ]; then. ~/.bashrc fi# User specific environment and startup programsPATH$PATH:$HOME/binexport PATH expo…...

5.3、【AI技术新纪元:Spring AI解码】图像生成API

Spring 图像生成API Spring图像生成API旨在提供一个简单且便携的接口,用于与各类专注于图像生成的AI模型交互,使开发者能够在不同图像相关模型之间轻松切换,只需对代码进行最少的改动。这一设计遵循了Spring框架的模块化和可互换性理念,确保开发人员能够快速调整其应用程序…...

自营、入驻商城小程序开发

IT外包的隐形重负——沟通成本&#xff1a;当客户仅能提供大致需求&#xff0c;而IT公司则机械地执行&#xff0c;往往会导致项目细节中充满漏洞&#xff0c;用户体验大打折扣。 最终&#xff0c;项目不断延期&#xff0c;进度一拖再拖。探究其根源&#xff0c;客户往往并非IT…...

C++关键字:const

文章目录 一、const的四大作用1.修饰 变量、数组2.修饰 函数的形参、修饰 引用 (最常用&#xff09;3.修饰 指针&#xff1a;常量指针、指针常量 、只读指针4.修饰 类的成员函数、修饰 类的对象 一、const的四大作用 1.修饰 变量、数组 1.const修饰变量&#xff1a; 被const修…...

nodejs 常用命令

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境&#xff0c;常用于服务器端编程。以下是一些 Node.js 的常用命令 1、安装 Node.js&#xff1a; 通常&#xff0c;你会从 Node.js 的官方网站下载并安装适合你操作系统的版本。安装完成后&#xff0c;你可以在命令行中…...

nginx配置详解+nginx_lua模块的使用

nginx基本配置详解 目录 nginx基本配置详解 nginx_lua模块使用方式 openresty介绍与安装 lua基本语法使用 全局配置&#xff1a; user&#xff1a;指定Nginx主进程运行的用户。在下方示例中&#xff0c;Nginx将以root用户身份运行。worker_processes&#xff1a;指定Ngi…...

大数据--hdfs--java编程

环境&#xff1a; virtualbox ubantu1604 Linux idea社区版2023 jdk1.8 hadoop相关依赖 使用java操作 1. 判断/user/stu/input/test.txt文件是否存在&#xff0c;存在则读出文件内容&#xff0c;打印在控制台上。反之&#xff0c;输出“文件不存在”。 package abc;impo…...

力扣由浅至深 每日一题.10 最后一个单词的长度

日子都是崭新的&#xff0c;我们下一章见 ——24.3.21 最后一个单词的长度 给你一个字符串 s&#xff0c;由若干单词组成&#xff0c;单词前后…...

21 OpenCV 直方图均衡化

文章目录 直方图概念均衡的目的equalizeHist 均衡化算子示例 直方图概念 图像直方图&#xff0c;是指对整个图像像在灰度范围内的像素值(0~255)统计出现频率次数&#xff0c;据此生成的直方图&#xff0c;称为图像直方图-直方图。直方图反映了图像灰度的分布情况。 均衡的目的…...

对七层代理、四层代理、正向代理、反向代理的认识

一、理解nginx服务代理 Nginx代理有正向和反向代理两种类型&#xff0c;可以基于osi七层模型中的第四层&#xff08;传输层&#xff09;和第七层&#xff08;应用层&#xff09;进行代理 注&#xff1a; nginx 一般支持的是7层代理&#xff0c;支持四层代理一般使用 lvs 或者ha…...

网络: 五种IO模型

阻塞IO: 在内核将数据准备好之前, 系统调用会一直等待. 所有的套接字, 默认都是阻塞方式 非阻塞IO:若内核还未将数据准备好, 系统调用仍然会直接返回, 并且返回EWOULDBLOCK错误码. 信号驱动: 内核将数据准备好的时候, 使用SIGIO信号通知应用程序进行IO操作 多路转接: 能够同时等…...

AI大模型学习在当前技术环境下的重要性与发展前景

目录 前言1 学科基础与技能要求1.1 数学基础的深厚性1.2 编程能力的必要性1.3 对特定领域业务场景的了解 2 模型结构与算法的优化2.1 模型结构的不断演进2.2 算法优化的重要性2.3 准确性与效率的提升 3 AI大模型学习的应用场景3.1 自然语言处理3.2 计算机视觉3.3 推荐系统 结语…...

【呼市经开区建设服务项目水、电能耗监测 数采案例】

实施方案 针对能耗采集中的水、电能源数据采集&#xff0c;因客观因素条件&#xff0c;数据采集方面存在较大难度。大多数国网电表485接口由于封签限制&#xff0c;不能实施采集&#xff0c;不让拆机接线&#xff0c;采集实施存在困难。水量能耗采集&#xff0c;存在类似问题&a…...

深度学习算法工程师面试常见问题及解答

基础知识和理论&#xff1a; 解释什么是深度学习以及它与机器学习的关系。描述神经网络的基本结构和工作原理。什么是反向传播算法&#xff0c;它是如何工作的&#xff1f;激活函数的作用是什么&#xff1f;常见的激活函数有哪些&#xff1f;什么是损失函数&#xff1f;常见的损…...

OKR与敏捷开发、精益创业等方法如何协同工作?

在快速变化的市场环境中&#xff0c;企业需要更加灵活和高效地应对各种挑战。目标与关键成果法&#xff08;OKR&#xff09;、敏捷开发以及精益创业等方法&#xff0c;作为现代企业管理的重要工具&#xff0c;各自在推动企业发展、提高团队效率、优化产品迭代等方面发挥着不可或…...

【ESP32 Arduino】定时器的使用

文章目录 前言一、ESPTIMER定时器的介绍1.1 定时器是什么 二、分频系数2.1 为什么需要分频系数2.2 分频系数怎么计算 三、定时器的使用3.1 初始化定时器对象3.2 设置中断时间3.3 设置回调函数3.4 使能定时器 四、示例代码总结 前言 在嵌入式系统中&#xff0c;定时器是一项重要…...

网络基础(一)初识

1、计算机网络背景 1.1、网络发展 1. 独立模式: 计算机之间相互独立&#xff1b; 2. 网络互联: 多台计算机连接在一起&#xff0c;完成数据共享&#xff1b; 3. 局域网LAN: 计算机数量更多了, 通过交换机和路由器连接在一起; 4. 广域网WAN: 将远隔千里的计算机都连在一起;…...

深度学习从心电信号中解码呼吸频率:原理、实现与临床价值

1. 项目概述&#xff1a;从心电信号中“听”到呼吸声呼吸频率&#xff0c;这个我们每分钟都在进行却很少被精确量化的生命体征&#xff0c;在临床医学中扮演着至关重要的角色。它不仅是评估呼吸系统功能的直接指标&#xff0c;更是反映全身代谢、循环乃至神经系统状态的“窗口”…...

AI时代程序员职业发展与个人创业可行性研究报告

一、行业宏观变革&#xff08;2026核心趋势数据佐证&#xff09; 1.1 开发范式已彻底重构&#xff08;行业不可逆拐点&#xff09; 2026年正式进入AI Agent智能体开发时代&#xff0c;传统CRUD编码价值持续崩塌。 核心权威数据&#xff1a; Gartner预测&#xff1a;2026年75%企…...

论文润色深度测评:GPT-5.5 + Gemini 3.1 Pro:教你学会1+1>2的论文润色方法

各位同仁好,我是七哥。一个在高校里从事人工智能相关领域研究,钻研用大模型AI实操的学术人。可以和七哥交流学术写作或Gemini、GPT、Claude等大模型学术实操相关问题,多多交流,相互成就,共同进步。 2026年的科研圈,AI工具的选择已经从有没有变成了强不强,七哥评测了GPT…...

Claude SWOT分析(内部风控文档流出版):3类高危使用场景+2个监管红线预警

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;Claude SWOT分析&#xff08;内部风控文档流出版&#xff09;&#xff1a;3类高危使用场景2个监管红线预警 高危使用场景识别 在企业级AI应用中&#xff0c;Claude模型若未经严格风控适配&#xff0c;…...

LVGL多页面开发避坑:用内部Timer替代轮询,解决页面切换时的内存踩踏问题

LVGL多页面开发中的内存安全实践&#xff1a;用Timer机制替代轮询的工程解决方案 在嵌入式UI开发中&#xff0c;LVGL因其轻量级和跨平台特性成为热门选择。但当项目复杂度提升到多页面交互时&#xff0c;开发者往往会遇到一个棘手问题&#xff1a;如何在频繁切换页面的同时保证…...

工业云脑:06 现在就能干:树莓派边缘盒子+PLC,10分钟缺陷检测小案例

06 现在就能干:树莓派边缘盒子+PLC,10分钟缺陷检测小案例 今天第九篇06小节——现在就能干:树莓派边缘盒子+PLC,10分钟缺陷检测小案例。新手照着做10分钟就能跑起来,老手一看就知道这玩意儿省了多少钱。以前想上AI检测,得花几万块买专业边缘盒子;现在?树莓派5(RPi 5)…...

纯硬件实现I2C协议:从逻辑门到传感器通信的深度实践

1. 项目概述&#xff1a;用纯硬件“解剖”I2C总线很多朋友在玩传感器&#xff0c;尤其是温湿度传感器时&#xff0c;都绕不开I2C这个通信协议。市面上绝大多数的教程和方案&#xff0c;都会告诉你&#xff1a;找个单片机&#xff08;比如Arduino、STM32&#xff09;&#xff0c…...

绝了!原来毕业论文还能这样写?2026降AIGC工具推荐合集

还在为查重率爆红、AI痕迹太明显、格式乱成一团而发愁&#xff1f;2026 年的 AI 论文工具早已不只是写文章那么简单&#xff0c;从选题构思到降AIGC率、去AI痕迹、查重优化&#xff0c;全流程智能辅助&#xff0c;帮你把论文写作变得简单高效&#xff0c;告别熬夜改稿的焦虑&am…...

Claude服务治理架构升级(生产环境零停机迁移实录)

更多请点击&#xff1a; https://codechina.net 第一章&#xff1a;Claude服务治理架构升级&#xff08;生产环境零停机迁移实录&#xff09; 为应对日益增长的推理请求量与多租户策略精细化需求&#xff0c;我们对Claude服务治理层实施了从单体API网关向云原生服务网格的平滑…...

安卓逆向实战:Frida内存砸壳提取DEX原理与技巧

1. 这不是“脱壳”&#xff0c;是逆向工程中一次精准的内存手术你打开一个加固过的安卓App&#xff0c;用常规工具解包&#xff0c;发现classes.dex只有几KB&#xff0c;里面全是混淆到面目全非的壳代码&#xff1b;用dex2jar反编译&#xff0c;报错“Not a valid dex file”&a…...