前端大文件上传

首先,我们需要使用Blob对象的 slice 方法将文件切分成多个切片。

const CHUNK_SIZE = 1024 * 1024; // 我们选择1MB作为每个切片的大小
let file = document.getElementById("upload").files[0]; // 得到所选文件
let totalSize = file.size;
let chunks = []; // 用于存储文件切片的数组
let start = 0; // 初始切片位置while (start < totalSize) {chunks.push(file.slice(start, start + CHUNK_SIZE));start += CHUNK_SIZE; // 移动切片的开始位置
}

(2) 文件合并:

有了文件切片后,我们需要在服务器端合并这些切片以重建文件。这通常在服务端完成,前端需要发送一个带有文件唯一标识的请求通知服务器所有切片已发送完毕,可以进行合并。

let fileName = file.name;
let fileId = fileName + '-' + totalSize; // 这是文件的唯一标识,也可使用其他方式
fetch('serverURL/merge', {method: 'POST',body: JSON.stringify({fileName, fileId}),headers: new Headers({'Content-Type': 'application/json'})
});

当我们在进行大文件切片上传时,可以通过在每个分片中包含一个切片的索引来保持切片的顺序。在接收分片的服务器端,可以根据这个索引来为每个分片分配合适的位置,这样即使上传的请求顺序发生了变化,服务器端仍然可以按照原始文件的顺序来组合这些分片。

在前端,你可以像下面这样为每个分片添加一个索引:

chunks.forEach((chunk, index) => {let chunkForm = new FormData();chunkForm.append('chunk', chunk);chunkForm.append('index', index); // 这里的 'index' 就是切片的索引 
});

在服务器端,你可以根据传入的 ‘index’ 来重新组合文件切片,即使分片以无序的方式接收,你仍然可以使用 ‘index’ 参数来保持它们的正确顺序,确保最后合并出来的文件与原文件一致。

例如,如果你在服务器端使用的是Node.js,可能会有类似下面的代码:

// 一个假设的处理文件分片上传的路由处理器
app.post('/upload', (req, res) => {let index = req.body.index; // 获得切片的索引// ...接下来,使用 'index' 来正确放置文件切片...
});

因此,通过为每个文件切片附加一个索引,我们可以确保在服务器端正确地重新组合这些切片,无论客户端以何种顺序发送这些切片。

(3) 断点续传:

要实现断点续传,需要在每次上传切片完成后在本地存储信息。在上传前检查本地是否有相关记录,若有,则跳过该切片,只上传未完成的部分。

let doneList= JSON.parse(localStorage.getItem(fileId)) || [];chunks.forEach((chunk, index) => {if(!doneList.includes(index)){  // 如果列表中没有本切片的索引,表示该切片未上传成功过let chunkForm = new FormData(); // 使用 FormData的方式发送切片chunkForm.append('chunk', chunk);chunkForm.append('index', index);chunkForm.append('fileId', fileId);fetch('serverURL/upload', {method: 'POST',body: chunkForm}).then(res => {doneList.push(index); // 上传完成后,将切片的索引放入doneList,并且存到localStoragelocalStorage.setItem(fileId, JSON.stringify(doneList));});}  
});

切片传输失败

判断文件切片是否上传成功的方式通常是通过服务器的响应来实现。在前端发送分片数据到服务器后,服务器会进行处理,如果分片数据被成功接收和存储,服务器通常会返回一个包含状态信息的响应。

在JavaScript中,你可以使用fetch API的.then()方法来处理服务器的响应:

chunks.forEach((chunk, index) => {fetch('serverURL/upload', {method: 'POST',body: chunkForm}).then(response => {if(response.ok) {console.log('切片 '+ index + ' 上传成功!');doneList.push(index); // 将成功上传的切片索引加入到doneList中localStorage.setItem(fileId, JSON.stringify(doneList));} else {console.log('切片 '+ index + ' 上传失败!');}}).catch(error => {console.log('网络错误:', error);})
});

在这个例子中,如果服务器成功处理了上传的切片,会返回一个状态为200的响应,这时,response.ok将为true,我们可以将该切片的索引加入到保存已上传切片的数组中。如果上传失败,或者网络出现错误,我们可以据此进行重试或者报告错误信息。

重试策略

1.处理上传失败的分片并重新上传的最常见策略是使用重试策略。我们可以设置一个最大重试次数,如果上传操作失败,我们会重新尝试上传分片,直到成功或达到最大重试次数。另一个常见策略是增加一个延时,在每次失败后等待一段时间再进行重试,这可以防止短时间内的过多无效尝试。

const MAX_RETRIES = 3; // 最大尝试次数function uploadChunk(chunk, index, retries = 0) {if (retries >= MAX_RETRIES) {console.log('切片 '+ index + ' 上传失败!');return;}fetch('serverURL/upload', {method: 'POST',body: chunkForm}).then(response => {if (!response.ok) throw new Error('Upload failed');console.log('切片 '+ index + ' 上传成功!');doneList.push(index); // 将成功上传的切片索引加入到doneList中localStorage.setItem(fileId, JSON.stringify(doneList));}).catch(error => {console.log('出现错误,准备重试:', error);setTimeout(() => uploadChunk(chunk, index, retries + 1), 1000); // 如果失败,等待1秒后重试});
}chunks.forEach((chunk, index) => {uploadChunk(chunk, index);
});

这个示例首先限制了最大尝试次数,如果达到这个次数,将停止尝试并记录失败信息。如果接收到分片的上传失败的信息,它将等待1秒钟然后重新尝试上传。这种方式可以有效地解决由暂时的网络问题引起的上传失败。

  1. 指数退避:
    指数退避(Exponential Backoff)是一种普遍用于优化网络通信的算法,这种算法通过控制网络请求之间的间隔时间来减少网络拥堵,特别是在由于网络错误而重试请求的场景中。

若要在切片上传失败时应用指数退避策略,你可以使用以下代码:

const MAX_RETRIES = 5; // 最大尝试次数
const RETRY_DELAY = 1000; // 1秒,基准等待时间function uploadChunk(chunk, index, retries = 0) {if (retries >= MAX_RETRIES) {console.log("切片 "+ index + " 上传失败!");return;}fetch('serverURL/upload', {method: "POST",body: chunkForm           // 假设 chunkForm 是你的 FormData 对象}).then(response => {if (!response.ok) throw new Error("Upload failed");console.log('切片 '+ index + ' 上传成功!');doneList.push(index);     // 将成功上传的切片索引加入到doneList中localStorage.setItem(fileId, JSON.stringify(doneList));}).catch(error => {console.log("上传失败,准备重试", error);// 如果上传切片失败,等待 RETRY_DELAY * (2 ** retries) 毫秒后再次尝试上传setTimeout(() => uploadChunk(chunk, index, retries + 1), RETRY_DELAY * (2 ** retries));});
}chunks.forEach((chunk, index) => {uploadChunk(chunk, index);
});

在这个例子中,RETRY_DELAY是重试之间的裸等待时间,并且每次失败后会增加重试的等待时间,等待时间计算方式为 RETRY_DELAY * (2 ** retries),即每次重试都将等待时间翻倍。这样可以给网络和服务器更多的恢复时间。

当达到MAX_RETRIES最大尝试次数后,就会停止重试并记录上传失败。

  1. 斐波那契退避:斐波那契退避是一种类似于指数退避的策略,不过它使用的是斐波那契数列而不是指数函数来计算下一次重试之前的暂停时间。

  2. 随机化间隔:为了防止多个客户端同时发起重试请求并再次使服务器过载(这种情况有时被称为“重试风暴”),一种策略是在每次重试之间添加一个随机化的等待时间。

  3. 使用重试库:有许多开源库可以使实施复杂的重试策略变得更容易。例如,在JavaScript中,你可以使用async-retry库来实现带有指数退避的重试。

以上就是文章全部内容了,如果喜欢这篇文章的话,还希望三连支持一下,感谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/17712.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Golang | Leetcode Golang题解之第103题二叉树的锯齿形层序遍历

题目&#xff1a; 题解&#xff1a; func zigzagLevelOrder(root *TreeNode) (ans [][]int) {if root nil {return}queue : []*TreeNode{root}for level : 0; len(queue) > 0; level {vals : []int{}q : queuequeue nilfor _, node : range q {vals append(vals, node.V…

什么是CSTP测试认证,如何通过CSTP认证?

什么是CSTP测试认证&#xff1f; CSTP&#xff08;Certified Software Test Professional&#xff09;认证是由国际软件测试认证委员会&#xff08;International Software Testing Qualifications Board, ISTQB&#xff09;制定的一种专业软件测试认证。该认证旨在提高软件测…

Java中获取运行时资源

Java中获取运行时资源 在Java中&#xff0c;将运行时资源&#xff08;如配置文件、图片、模板文件等&#xff09;放在类路径&#xff08;classpath&#xff09;中的某个位置。 使用getResource()方法 URL resourceUrl getClass().getClassLoader().getResource("confi…

C#算法(15)—求四边形的外接矩形

前言 在上位机软件开发的过程中,我们经常需要一个四边形的外接矩形,这个外接矩形通常有两种一种是正外接矩形,一种是最小面积的最小外接矩形,最常见的应用是我们需要从一个四边形中截取一部分图像,然后对这个截取出来的图像进行处理,下面分别介绍这两种外接矩形的求法 …

物联网架构实例—Ubuntu 安装MySQL

1.ubuntu安装mysql apt-get upgrade apt-get update 安装mysql apt-get install mysql-server Y执行安装后&#xff0c;会来到软件包设置界面. 再次确认设置的密码. 开启mysql的服务 service mysql start 确认是否成功开启mysql service mysql status 确认是否启动成功&a…

Java Object类方法介绍

Object作为顶级类&#xff0c;所有的类都实现了该类的方法&#xff0c;包括数组。 查询Java文档&#xff1a; 1、object.eauqls(): 其作用与 有些类似。 &#xff1a; 是一个比较运算符&#xff0c;而不是一个方法。 ①可以判断基本类型&#xff0c;也可以判断引用类型。 ②若…

gitLab 使用tortoiseGit 克隆新项目 一直提示tortoiseGitPlink输入密码 输完也不生效

问题描述&#xff1a;准备用TortoiseGit拉取gitlab上一个新项目代码&#xff0c;出现tortoiseGitPlink提示让输入密码&#xff0c;输入后又弹出&#xff0c;反复几次&#xff0c;无法down下来代码。 解决方案&#xff1a; 1.找到PuTTYgen工具&#xff0c;打开 2. 点击load 按钮…

Git之创建完美提交

创建完美提交 是否还在把Git当中一个无聊的备份系统吗&#xff1f;是否还在git add .?只要发生修改就塞进提交里&#xff0c;提交会失去很多价值。提交和提交之间的分界很随意。之后再看这些提交&#xff0c;就像再家里翻箱倒柜的找东西&#xff0c;很难找到想要的东西。 整…

山脉数组的峰顶索引 ---- 二分查找

题目链接 题目: 分析: 我们很明显, 可以从峰值位置将数组分成两段, 具有"二段性", 所以可以用二分查找因为arr是山峰数组, 不存在相等的情况如果arr[mid] > arr[mid 1], 说明mid的位置可能是峰值, 移动right mid如果arr[mid] < arr[mid 1], 说明mid的位置…

神奇的一万

在代码界&#xff0c;有个神奇的存在&#xff0c;它叫一万&#xff1a;eval&#xff08;&#xff09;。 这个神奇的一万&#xff0c;在python和JavaScript中都存在&#xff0c;作用也是基本相同的。 Python中的eval函数能将字符串str当成有效的表达式来求值并返回计算结果。 …

vue contextPath的思考

先说我这边的情况&#xff0c;目前项目都是前后端分离开发的&#xff0c;上线有种部署方式&#xff0c;常见的就是前后端分开部署&#xff0c;这是比较常见的&#xff0c;我这边因客户原因&#xff0c;打包一起进行部署比较简单&#xff0c;交付技术运维部方便后期其他现场部署…

qt c++ can通信实现的上位机界面,附源码

qt c can通信实现的上位机界面&#xff0c;附源码

docker ps显示的参数具体是什么意思

1&#xff0c;运行一个容器 docker run -d ubuntu:15.10 /bin/sh -c "while true; do echo hello world; sleep 1; done"这段命令的作用是使用 docker run 命令运行一个基于 ubuntu:15.10 镜像的 Docker 容器&#xff0c;并在容器中执行一个无限循环的命令。 具体解…

10Django项目--用户管理系统--改

对应视频链接点击直达 10Django项目--用户管理系统--改 对应视频链接点击直达改a&#xff0c;本质b&#xff0c;修改(更新) 页面相关a&#xff0c;index页面新增操作按钮b&#xff0c;修改(更新)页面c&#xff0c;路由和函数 OVER&#xff0c;不会有人不会吧不会的加Q139400651…

viewer.js 在layui中使用,并且实现表格中点击预览,点击图片名称定位到表格中某一条数据并高亮显示

下载viewer.js到本地&#xff0c;并在页面中引入 下载地址: https://www.dowebok.com/demo/192/ 页面引入js和css <link rel"stylesheet" href"/plugins/viewer/viewer.min.css" th:href"{/plugins/viewer/viewer.min.css}"> <scri…

基于jeecgboot-vue3的Flowable流程-我的任务(一)

因为这个项目license问题无法开源&#xff0c;更多技术支持与服务请加入我的知识星球。 1、首先可以用现成生成代码的前端来做这个&#xff0c;只要做一些调整就可以了&#xff0c;这样利用现有的一些模板可以快速构建我的任务&#xff0c;否则vue2与vue3相差太大&#xff0c;移…

【设计模式】生成器

来源&#xff1a;爱编程的大丙 复杂的问题化繁为简&#xff0c;逐个击破。也就是分步骤创建复杂的对象&#xff0c;并允许使用相同代码生成不同类型和形式的对象&#xff0c;这种模式叫做生成器模式&#xff08;也叫建造者模式&#xff09;。 生成器模式建议将造船工序的代码…

质量人,你还在等什么?快来六西格玛培训公司充电吧!——张驰咨询

在竞争激烈的商业环境中&#xff0c;质量成为了企业生存和发展的关键。而六西格玛&#xff0c;作为一种全球公认的质量管理方法论&#xff0c;正在成为越来越多企业追求品质革命的重要工具。而六西格玛培训公司&#xff0c;则成为了这场品质革命中&#xff0c;质量人不可或缺的…

mysql数据库管理面试题-1

1. 描述MySQL架构及其主要组件&#xff08;例如存储引擎、缓存、优化器等&#xff09;。 MySQL的架构可以分为三层&#xff1a; 客户端层&#xff1a;这是用户和MySQL数据库交互的接口&#xff0c;包括命令行工具、图形化管理工具等。 服务层&#xff1a;这是MySQL的核心部分…

菊花链通信技术整理

目录 一、菊花链简介 二、菊花链与CAN通信的区别 三、常见的菊花链AFE芯片 四、菊花链数据结构 五、菊花链方案介绍 一、菊花链简介 首先简单的说一下菊花链以及菊花链的应用&#xff0c;在目前国内的BMS开发中&#xff0c;我们应用最广泛的目前还还是分布式&#xff0c;…