前端大文件分片上传

news2024/11/27 10:31:25

1.分片上传整体流程

  • 开始上传:前端启动文件分片上传。后端返回唯一标识。
  • 分片上传:获取到上传的文件,然后设置一个固定的分片大小,将文件切成多个小片,计算出每一个分片的MD5值(32位)。将每个分片的内容和MD5标识符一同上传至服务器。服务端接收每个分片及相关信息后,通过对每个分片进行校验,来确保分片的完整性。
  • 结束上传:当分片上传完毕或者前端取消上传时,调用结束上传接口结束此次文件上传操作。结束上传时,服务端判断是正常结束或取消上传来决定后续操作。

2.前端具体流程

  • 开始上传,发送开始上传请求,向服务器传递文件名、文件总大小、分片总数和切片大小,获取并保存文件上传的唯一标识符。同时在发送请求前,对上传的文件名进行校验,如果文件名超过最大长度256,则禁止发送请求并向用户提示修改文件名称。
  • 分片上传,首先将文件进行切片,调用切片方法时,需要将文件传递给该方法,然后根据文件的大小来决定每个分片的大小并切分成多个片段,同时计算出总切片数,并为每个切片添加从0开始的顺序索引。随后对每个切片计算出他们的MD5值。最后把这些分片的MD5值和顺序索引保存在浏览器内存中。然后发送上传数据请求,向服务器发送唯一标识符、分片的顺序索引、分片数据,MD5值和当前分片的大小。在每个分片发送请求后,如果发送成功,则将其对应的信息从浏览器内存中删除,并计算出此时的上传进度,然后发送下一个片段直至最后。如果全部上传成功,清空浏览器内存。如果请求发生错误,则对该分片再次发送一次上传请求,如果仍然错误,不再上传,调用结束请求并提示错误原因。
  • 结束上传,如果文件分片全部成功上传,向服务器发送结束请求,传递正常结束状态码,清空浏览器内存。如果主动取消上传则传递取消请求状态码,同时清空浏览器内存,不再继续上传。

3.部分代码

//文件切片,utils

import SparkMD5 from 'spark-md5'

export async function getChunkList (files) {
	const file = files
	console.log(file);
	const fileSize = file.size // 文件大小
	const fileName = file.name

	let chunkSize = 0;
	if (fileSize <= 5 * 1024 * 1024) { // 0-5M,不分片
		chunkSize = fileSize;
	} else if (fileSize <= 20 * 1024 * 1024) { // 5-20M,每个分片大小1M
		chunkSize = 1024 * 1024;
	} else if (fileSize <= 50 * 1024 * 1024) { // 20-50M,每个分片大小2M
		chunkSize = 2 * 1024 * 1024;
	} else if (fileSize <= 100 * 1024 * 1024) { // 50-100M,每个分片大小4M
		chunkSize = 4 * 1024 * 1024;
	} else if (fileSize <= 200 * 1024 * 1024) { // 100-200M,每个分片大小6M
		chunkSize = 6 * 1024 * 1024;
	} else if (fileSize <= 500 * 1024 * 1024) { // 200-500M,每个分片大小10M
		chunkSize = 10 * 1024 * 1024;
	} else if (fileSize <= 1024 * 1024 * 1024) { // 500M-1G,每个分片大小20M
		chunkSize = 20 * 1024 * 1024;
	} else { // 1G以上,每个分片大小20M
		chunkSize = 20 * 1024 * 1024;
	}
	const totalChunks = Math.ceil(fileSize / chunkSize)
	let start = 0
	let end = Math.min(chunkSize, fileSize)
	let index = 0 // 分片索引,从0开始
	const chunks = [] // 存储当前文件的分片信息的数组

	while (start < fileSize) {
		const chunk = file.slice(start, end)
		const reader = new FileReader()
		const promise = new Promise((resolve, reject) => {
			reader.onload = (e) => { //读取文件分片信息,使用SparkMD5库计算分片的MD5值
				const spark = new SparkMD5.ArrayBuffer()
				spark.append(e.target.result)
				resolve(spark.end())
			}
			reader.onerror = (err) => {
				reject(err)
			}
		})
		reader.readAsArrayBuffer(chunk)
		try {
			const md5 = await promise
			const chunkInfo = { chunk, md5, index }
			chunks.push(chunkInfo)
		} catch (err) {
			reject(err)
		}
		//更新循环起止位置
		start = end
		end = Math.min(start + chunkSize, fileSize)
		index++
	}
	// 将当前文件的分片信息数组存入总的数组中
	return [chunks, totalChunks, fileSize, fileName, chunkSize] // 返回存储所有文件的分片信息的数组
} 	
async handleUpload () {
			this.progressState = 'upload'
			this.wrongNum = 0
			if (this.fileList.length == 0) { //判断是否添加文件
				this.$notify.warning({
					title: this.$global.warningMessage.title,
					message: this.$global.warningMessage.fileMessage,
				});
				return
			}
			if (this.file.name.length > 256) {
				this.$notify.warning({
					title: this.$global.warningMessage.title,
					message: this.$global.warningMessage.fileNameMessage,
				});
				return
			}
			this.totalSize = this.file.size
			// 调用getChunkList方法获取分片及相关信息
			const [chunks, totalChunks, fileSize, fileName, chunkSize] = await getChunkList(this.file.raw)
			this.totalChunks = totalChunks
			this.fileSize = fileSize
			this.fileName = fileName
			this.chunkList = chunks
			this.chunkSize = chunkSize
			console.log(this.chunkList);
			// 开始上传请求
			await this.startUpload()
			// 遍历分片信息数组,取出除文件分片外的其他信息
			const sessionChunkList = this.chunkList.map(({ chunk, ...rest }) => rest);
			// 将分片其他信息存入sessionStorage中
			sessionStorage.setItem("chunkData", JSON.stringify(sessionChunkList));
			let i = 0;
			while (i < this.chunkList.length && this.wrongNum < 1) { //对分片数组进行遍历
				const chunkInfo = this.chunkList[i];
				const res = await this.uploadChunk(chunkInfo); //调用上传分片方法
				if (res.data.state == 200) {
					const removeInfo = {
						md5: chunkInfo.md5,
						index: chunkInfo.index
					}
					await this.handleSuccess(removeInfo, chunkInfo) //调用当前分片上传成功处理函数
					i++;
				} else {   //上传未成功,重新上传一次
					const res = await this.uploadChunk(chunkInfo);
					this.wrongNum += 1
					if (res.data.state == 200) {
						this.wrongNum = 0
						await this.handleSuccess(removeInfo, chunkInfo)
						i++;
					} else {  // 重新上传一次后仍未成功
						const state = this.$global.completeUploadState.cancelUpload
						await this.completeUpload(state)
						this.$notify.error({
							title: this.$global.failedMessage.title,
							message: res.data.message
						});
						this.handleClear()
						return
					}
				}
			}
		}

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

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

相关文章

新model开发记录

模型使用 -- 用blender导出为 fbx &#xff0c;修改渲染方式&#xff08;点击模型->Materials->Extract Materials(将材质从fbx中 单独提取出来了)->Materials 选择 Shader -> SimpleURPToonLitExample 点开脸的材质&#xff0c;勾选第一条&#xff09; 解决角色…

【Redis】redis集群模式

概述 Redis集群&#xff0c;即Redis Cluster&#xff0c;是Redis 3.0开始引入的分布式存储方案。实际使用中集群一般由多个节点(Node)组成&#xff0c;Redis的数据分布在这些节点中。集群中的节点分为主节点和从节点&#xff1a;只有主节点负责读写请求和集群信息的维护&#…

基于OSPF的企业内网安全优化

1.拓扑 2.IP地址规划 设备/地址/vlan设备/地址汇聚交换机/VLAN10192.200.10.0/24汇聚交换机/VLAN20192.200.20.0/24汇聚交换机/VLAN30192.200.30.0/24汇聚交换机/VLAN40192.200.40.0/24汇聚交换机/VLAN50192.200.50.0/24汇聚交换机/VLAN60192.200.60.0/24防火墙/VLAN70/服务器…

【面试八股总结】传输控制协议TCP(二)

参考资料 &#xff1a;小林Coding、阿秀、代码随想录 一、TCP报文段首部 TCP 虽然是面向字节流的&#xff0c;但 TCP 传送的数据单元却是报文段。 一个 TCP 报文段分为首部和数据两部分&#xff0c;TCP 报文段首部的前 20 个字节是固定的&#xff0c;后面有 4n 字节是根据需要…

MongoDB 启动异常

Failed to start up WiredTiger under any compatibility version. 解决方案: 删除WiredTiger.lock 和 mongod.lock两个文件&#xff0c;在重新启动。回重新生成新的文件。

vue3源码解析——ref和reactive定义响应式的区别

ref 和 reactive 是 Vue 3.0 中用于定义响应式数据的两个新 API。它们有以下区别&#xff1a; ref 定义单个响应式数据 数据类型可以是任意类型。它通常用于定义原始数据类型为响应式数据。返回一个响应式对象&#xff0c;该对象包含一个 .value 属性&#xff0c;可用于获取和设…

【滤波器基础】卡尔曼滤波器

滤波器基础 为了进一步抑制高频噪声&#xff0c;科研人员也会采用一些高阶低通滤波器来对电流采样信号的高频噪声进行抑制&#xff0c;常用的一种滤波器为&#xff1a;巴特沃兹滤波器。除了这种滤波器&#xff0c;也存在如贝塞尔、切比雪夫滤波器等。 巴特沃斯滤波器 在线性控…

linux自动化运维之ansible实战

ansible基础介绍 优点 - 相比于saltatack和puppet&#xff0c;没有客户端&#xff0c;更轻量级 - 只是一个工具&#xff0c;可以很容易实现分布式拓展 - 更强的远程执行命令 特点 - 模块化 - 支持自定义模块&#xff0c;可以用任何语言编写模块 - 基于python语言实现 - 部署简单…

深度学习实战73-基于多模态CLIP模型的实战项目,CLIP模型的架构介绍与代码实现

大家好,我是微学AI,今天给大家介绍一下深度学习实战73-基于多模态CLIP模型的实战项目,CLIP模型的架构介绍与代码实现。多模态CLIP(Contrastive Language-Image Pre-training)模型是一种深度学习模型,其核心设计理念是通过大规模的对比学习训练,实现图像与文本之间的跨模…

前端调试工具之Chrome Elements、Network、Sources、TimeLine调试

常用的调试工具有Chrome浏览器的调试工具&#xff0c;火狐浏览器的Firebug插件调试工具&#xff0c;IE的开发人员工具等。它们的功能与使用方法大致相似。Chrome浏览器简洁快速&#xff0c;功能强大这里主要介绍Chrome浏览器的调试工具。 打开 Google Chrome 浏览器&#xff0c…

便携式气象站是什么

TH-BQX5便携式气象站是一种用于应对突发天气灾害和紧急情况的便携式气象监测设备。它通常包括气温、湿度、气压、风速、风向和降水量等关键气象要素的测量功能&#xff0c;能够快速准确地记录这些气象参数。此外&#xff0c;一些高级的便携式气象站还具备预警功能&#xff0c;当…

阿里云学习笔记

1、什么是IaaS&#xff0c;PaaS和SaaS&#xff1f; IaaS、PaaS 和 SaaS 是云计算服务的三种主要模式&#xff0c;它们分别代表了不同的服务层级&#xff0c;按照由低到高的抽象程度排序如下&#xff1a; IaaS (Infrastructure as a Service) 基础设施即服务 提供的是底层的计…

Three.js——创建场景、渲染三维对象、添加灯光、添加阴影、添加雾化

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

早起的“鸟儿”有虫吃:如何在 App 运行的极早期执行代码?

功能需求 在某些开发场景中,我们希望能够在 App 运行时尽早执行一段代码,不求最早但求更早! 如上图所示,我们将会讨论在 App 生命早期运行代码的 5 种方法,小伙伴们可能会大吃一惊:applicationDidFinishLaunching 之类的方法竟然是最晚得到执行的! 在本篇博文中,您将…

mysql高阶之(视图)

目录 视图概念 视图概念 视图是基于一个或多个表的SQL查询结果的虚拟表。视图并不实际存储数据&#xff0c;而是保存了查询的定义。当你查询视图时&#xff0c;数据库引擎会按照视图的定义执行底层的SQL查询。 &#xff08;一&#xff09;视图作用 视图的主要作用时一张表或多…

Mysql故障和优化

一、MySQL故障 二、MySQL优化 1.硬件优化&#xff1a; 2.数据库设计与规划 1.提前估计数据量&#xff0c;使用什么存储引擎 2.数据库服务器专机专用&#xff0c;避免额外的服务可能导致的性能下降和不稳定性 3.增加多台服务器&#xff0c;以达到稳定、高效的效果。主从同步、…

Python中的相关规则:注释,参数,模块和包

Python中的相关规则&#xff1a;注释&#xff0c;参数&#xff0c;模块和包 注释参数模块包(package)数据类型其他一些编写代码小技巧 注释 crtl/注释&#xff0c;多行注释&#xff08;三对单引号或双引号&#xff09;&#xff1a;多行注释一般放在文件开头&#xff0c;标明整个…

Linux之实现Apache服务器监控、数据库定时备份及通过使用Shell脚本发送邮件

目录 一、Apache服务器监控 为什么要用到服务监控&#xff1f; 实现Apache服务器监控 二、数据库备份 为什么要用到数据库备份&#xff1f; 实现数据库备份 三、Shell脚本发送邮件 为什么要用使用Shell脚本发送邮件&#xff1f; 实现Shell脚本发送邮件 一、Apache服务器…

算法——所有可能的真二叉树:递归

. - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a;递归。因为要是真二叉树&#xff0c;节点树必为奇数个。 对于左子树和右子树分别递归构造&#xff0c;左子树从1开始一直到n-2&#xff0c;右子树从n-2开始一直到1&#xff1b; 然后使用数组接受左右子树构造出来的…

Annaconda的替代品miniforge!

用了多年的Annaconda竟然要收费了&#xff08;个人不收费&#xff0c;企业收费&#xff0c;但个人电脑在企业IP下&#xff0c;还是被警告了&#xff09;&#xff0c;只能用miniforge 全面替换了&#xff01; 一、卸载anaconda windows下卸载&#xff0c; 设置 -> 应用和功…