Vue 大文件切片上传实现指南包会,含【并发上传切片,断点续传,服务器合并切片,计算文件MD5,上传进度显示,秒传】等功能

Vue 大文件切片上传实现指南

背景

        在Web开发中,文件上传是一个常见的功能需求,尤其是当涉及到大文件上传时,为了提高上传的稳定性和效率,文件切片上传技术便显得尤为重要。通过将大文件切分成多个小块(切片)进行上传,不仅可以有效减少单次上传的数据量,降低网络波动对上传过程的影响,还能实现如断点续传、秒传等高级功能。本文将以Vue为框架,配合 Axios 进行 HTTP 请求,详细介绍如何实现一个支持文件切片上传的功能。

前端准备工作

        在开始编码之前,请确保你的项目中已经安装了 axiosspark-md5 两个库。axios 用于发起网络请求,spark-md5 用于计算文件的 MD5 值,从而支持秒传和断点续传功能。

前端需要实现的功能

  1. 文件选择和限制:

    通过<input type="file" @change="handleFileChange" accept="video/*" />实现了文件的选择,同时限制了用户只能选择视频文件进行上传。

  2. 计算文件的MD5值

    computeFileHash方法中,利用SparkMD5库计算用户选中文件的MD5值。这一步是为了之后能够校验文件的完整性和唯一性。

  3. 校验文件是否需要上传

    checkFile方法中,通过向服务器查询文件的MD5值,判断该文件是否已经上传过,以此实现秒传功能,避免重复上传相同文件。

  4. 文件切片

    sliceFileAndUpload方法中,将大文件切割成多个小片段(切片),这样做的目的是为了支持大文件的分块上传,提高上传效率,同时也便于出错时重新上传单个切片而不是整个文件。

  5. 并发上传切片

    通过processPooluploadChunk方法实现切片的并发上传,限制了最大并发数(MAX_REQUEST),以免过多并发请求压崩服务器。

  6. 上传进度反馈

    通过uploadProgress数据和模板中的进度显示,用户可以实时看到文件上传的进度。

  7. 服务器通知合并切片

    在所有切片上传完成后,通过notifyServerToMerge方法向服务器发送通知,请求服务器端进行切片的合并,以重建原始文件。

后端需要支持的API接口

为了支持前端的大文件上传和处理逻辑,后端需要提供以下API接口:

  1. 文件校验API
  • 功能:检查文件的完整性和上传状态。这通常通过文件的唯一标识(如MD5哈希值)来实现。
  • 输入参数:文件唯一标识(如MD5哈希值)。
  • 返回值:告知客户端该文件是否已经存在,如果存在,是否完整。如果文件已经存在且不完整,则返回已上传的切片信息。
  1. 切片上传API
  • 功能:接收文件的单个切片,并保存到服务器的临时存储位置。
  • 输入参数:文件的唯一标识,切片内容,切片的序号。
  • 返回值:确认切片上传成功或失败的状态。
  1. 切片合并API
  • 功能:将所有上传的切片合并成一个完整的文件。
  • 输入参数:文件的唯一标识,可能还包括文件名、总切片数等信息。
  • 返回值:合并操作的成功或失败状态,以及最终文件的访问URL(可选)。
  1. 上传进度查询API
  • 功能:查询文件上传的进度,这对于恢复上传和提供用户反馈非常有用。
  • 输入参数:文件的唯一标识。
  • 返回值:已上传的切片列表或上传进度百分比。

这些API合起来支持了一个分块上传文件的完整流程,包括文件的校验切片的上传切片的合并,以及上传进度查询。这个流程可以有效地处理大文件上传,减少网络传输的负担,提高上传的可靠性,并允许上传过程中的暂停和恢复

执行流程

        一开始用户通过界面选择一个文件进行上传,进行文件选择,用户通过文件选择框悬着一个大文件,比如视频文件,触发handleFileChange方法,然后再计算这个大文件的MD5,使用computeFileHash方法计算选中文件的MD5哈希值,计算完成后检查文件是否需要上传,向服务器发起请求,根据文件的MD5哈希值执行checkFile方法检查文件是否已经存在,如果文件已经存在通知用户秒传功能并将上传进度设为100%,如果文件需要上传,则使用sliceFileAndUpload方法将文件切成很多个小块,每个切片及其索引都被添加到requestPool请求池中,从requestPool中并发上传切片processPool方法,对每个切片调用uploadChunk方法进行实际上传,通过MAX_REQUEST控制并发上传的数量,没上传一个切片,uploadChunksCount增加,并更新上传进度。所有切片上传完成后,通知服务器合并这些切片notifyServerToMerge,当服务器成功合并所有切片成原始后,整个切片上传流程完成。

实现步骤

步骤一:用户选择文件

        用户通过 <input type="file"> 选择文件后,handleFileChange 事件被触发。在这个事件处理函数中,我们首先获取到用户选择的文件,然后计算文件的 MD5 值,以此作为文件的唯一标识。这一步是实现断点续传秒传功能的关键。

<template><div><!-- 文件选择框,仅接受视频文件 --><input type="file" @change="handleFileChange" accept="video/*" /><!-- 上传按钮 --><button @click="handleUpload">Upload</button><!-- 上传进度显示 --><div v-if="uploadProgress > 0">Upload Progress: {{ uploadProgress }}%</div></div>
</template>

步骤二:计算文件 MD5

        使用 spark-md5 库计算文件的 MD5 值。通过FileReader API 读取文件内容,然后计算其 MD5 值。这个过程可能会花费一些时间,因此使用 Promise 来异步处理。

async computeFileHash(file) {const spark = new SparkMD5.ArrayBuffer();const fileReader = new FileReader();return new Promise((resolve) => {fileReader.onload = (e) => {spark.append(e.target.result);const hash = spark.end();resolve(hash);};fileReader.readAsArrayBuffer(file);});
}

步骤三:检查文件状态,检查文件是否已经上传还是部分上传

        在上传文件之前,先向服务器发送请求,检查这个文件是否已经部分或全部上传过。这一步是实现断点续传的关键。服务器根据文件的 MD5 值返回已上传的切片信息或表示文件完全上传的状态。

 // 向服务器查询文件是否已经部分或完全上传
async checkFile(fileHash) {  <---  此处应替换为你的接口调用代码  --->// 假设接口返回 { shouldUpload: boolean, uploadedChunks: Array<number> }return { shouldUpload: true, uploadedChunks: [] };
},

步骤四:切片并准备上传

        根据服务器返回的信息,如果文件未完全上传,我们将文件分割成多个切片。然后根据已上传的切片信息,跳过那些已经上传的切片,仅上传剩余的切片。
        切片并准备上传在sliceFileAndUpload方法中实现。这个方法首先计算了整个文件应该被分割成多少切片(基于设定的切片大小),然后根据服务器返回的已上传切片信息(uploadedChunks),它会跳过这些已经上传的切片,只将剩余的切片添加到请求池(requestPool)中准备上传。

 // 切片并准备上传
sliceFileAndUpload(fileHash, uploadedChunks) {const chunkSize = 10 * 1024 * 1024; // 切片大小,这里是10MBthis.chunkCount = Math.ceil(this.selectedFile.size / chunkSize); // 计算总切片数this.uploadProgress = 0; // 重置上传进度for (let i = 0; i < this.chunkCount; i++) {if (uploadedChunks.includes(i)) continue; // 跳过已上传的切片const chunk = this.selectedFile.slice(i * chunkSize, (i + 1) * chunkSize); // 获取切片this.requestPool.push({ chunk, index: i }); // 加入请求池}this.processPool(fileHash); // 开始处理请求池},

上面这段代码中,uploadedChunks参数是一个数组,包含了所有已上传切片的索引。通过检查当前切片的索引是否包含在这个数组中,代码决定是否跳过当前切片的上传。如果索引不在uploadedChunks中,这意味着该切片还没有被上传,因此需要将其添加到requestPool中等待上传。这样,只有那些未上传的切片会被实际上传,从而实现了断点续传的功能。processPool进行并发切片上传

步骤五:并发上传切片

        为了提高上传效率,我们使用并发上传的方式。设置最大并发数,控制同时上传的切片数量。通过逐一上传切片,并监听每个上传请求的完成,从而动态调整并发请求。
        并发上传切片的逻辑主要在processPool方法中实现。这个方法负责管理并发请求,确保同时只有一定数量的上传请求在处理中。这通过一个简单的请求池(requestPool)和控制最大并发数量(MAX_REQUEST)来实现。

// 处理请求池中的切片上传
processPool(fileHash) {while (this.requestPool.length > 0 && this.MAX_REQUEST > 0) {const { chunk, index } = this.requestPool.shift(); // 取出一个待上传的切片this.uploadChunk(chunk, fileHash, index) // 上传切片.then(() => {this.uploadedChunksCount++; // 更新已上传切片数量this.uploadProgress = ((this.uploadedChunksCount / this.chunkCount) * 100).toFixed(2); // 更新上传进度if (this.requestPool.length > 0) {this.processPool(fileHash); // 继续处理请求池} else if (this.uploadedChunksCount === this.chunkCount) {// 所有切片都已上传,通知服务器合并this.notifyServerToMerge(fileHash);}}).finally(() => {this.MAX_REQUEST++; // 释放一个请求槽});this.MAX_REQUEST--; // 占用一个请求槽}
},

        在这个方法中,while循环检查请求池中是否还有待处理的切片,并且当前活跃的请求数量是否小于允许的最大并发数量MAX_REQUEST。如果这两个条件都满足,它会从请求池中取出一个切片,并调用uploadChunk方法来上传它,同时减少MAX_REQUEST的值来反映一个新的请求已经开始。
        当一个切片上传完成后,then回调函数会增加已上传切片的计数并更新上传进度。如果请求池中还有待上传的切片,它会递归调用processPool来处理下一个切片。一旦所有切片都上传完成,它会调用notifyServerToMerge来通知服务器所有切片已经上传完毕,可以合并成一个完整的文件。通过这种方式,代码能够在保持最大并发限制的同时,高效地处理切片的上传。

步骤六:服务器合并切片

        所有切片上传完成后,客户端向服务器发送一个合并切片的请求。服务器接收到请求后,将所有切片合并成原始文件,并返回合并结果。

// 通知服务器合并切片
notifyServerToMerge(fileHash) {// 通知服务器合并切片,应替换为真实的合并API调用console.log(`通知服务器将文件与哈希合并: ${fileHash}`);
},

        一个API调用,向服务器发送一个请求来触发合并已上传切片的操作。这个请求通常会携带一些必要的信息,比如文件的唯一标识(在这个例子中是fileHash),以及可能还有其他诸如文件名文件大小切片数量等信息,这些信息取决于服务器端合并切片的具体要求。
        服务器收到合并请求后,会根据提供的信息找到所有相关的切片,按正确的顺序将它们合并成一个完整的文件,并将该文件存储在服务器上的适当位置。完成这个过程后,服务器可能还会向客户端发送一个响应,通知合并操作的结果(成功或失败),以及可能的后续步骤或需要的信息。
        通过上述步骤,实现了一个高效稳定的大文件上传功能,极大提升了用户体验。

全部代码

<template><div><!-- 文件选择框,仅接受视频文件 --><input type="file" @change="handleFileChange" accept="video/*" /><!-- 上传按钮 --><button @click="handleUpload">Upload</button><!-- 上传进度显示 --><div v-if="uploadProgress > 0">Upload Progress: {{ uploadProgress }}%</div></div>
</template><script>
import axios from "axios";
import SparkMD5 from "spark-md5"; // 引入SparkMD5用于计算文件的MD5值export default {data() {return {selectedFile: null, // 用户选择的文件uploadProgress: 0, // 上传进度requestPool: [], // 请求池,存储待上传的切片信息MAX_REQUEST: 6, // 最大并发请求数量chunkCount: 0, // 文件切片总数uploadedChunksCount: 0, // 已上传的切片数量};},methods: {// 处理文件选择事件async handleFileChange(event) {this.selectedFile = event.target.files[0];if (!this.selectedFile) return; // 未选择文件则返回// 可以在这里添加文件格式校验const fileHash = await this.computeFileHash(this.selectedFile); // 计算文件hashconst { shouldUpload, uploadedChunks } = await this.checkFile(fileHash); // 检查文件是否需要上传if (!shouldUpload) {alert("文件已存在,秒传成功!");this.uploadProgress = 100; // 直接设置进度为100%return;}this.sliceFileAndUpload(fileHash, uploadedChunks); // 切片并上传},// 计算文件的MD5computeFileHash(file) {return new Promise((resolve) => {const spark = new SparkMD5.ArrayBuffer();const fileReader = new FileReader();fileReader.onload = (e) => {spark.append(e.target.result);const hash = spark.end();resolve(hash); // 返回计算得到的hash值};fileReader.readAsArrayBuffer(file);});},// 检查文件是否已经上传过async checkFile(fileHash) {// 应替换为真实的API调用来检查文件状态return { shouldUpload: true, uploadedChunks: [] }; // 模拟返回值},// 切片并准备上传sliceFileAndUpload(fileHash, uploadedChunks) {const chunkSize = 10 * 1024 * 1024; // 切片大小,这里是10MBthis.chunkCount = Math.ceil(this.selectedFile.size / chunkSize); // 计算总切片数this.uploadProgress = 0; // 重置上传进度for (let i = 0; i < this.chunkCount; i++) {if (uploadedChunks.includes(i)) continue; // 跳过已上传的切片const chunk = this.selectedFile.slice(i * chunkSize, (i + 1) * chunkSize); // 获取切片this.requestPool.push({ chunk, index: i }); // 加入请求池}this.processPool(fileHash); // 开始处理请求池},// 处理请求池中的切片上传processPool(fileHash) {while (this.requestPool.length > 0 && this.MAX_REQUEST > 0) {const { chunk, index } = this.requestPool.shift(); // 取出一个待上传的切片this.uploadChunk(chunk, fileHash, index) // 上传切片.then(() => {this.uploadedChunksCount++; // 更新已上传切片数量this.uploadProgress = ((this.uploadedChunksCount / this.chunkCount) * 100).toFixed(2); // 更新上传进度if (this.requestPool.length > 0) {this.processPool(fileHash); // 继续处理请求池} else if (this.uploadedChunksCount === this.chunkCount) {// 所有切片都已上传,通知服务器合并this.notifyServerToMerge(fileHash);}}).finally(() => {this.MAX_REQUEST++; // 释放一个请求槽});this.MAX_REQUEST--; // 占用一个请求槽}},// 上传单个切片async uploadChunk(chunk, fileHash, index) {const formData = new FormData();formData.append("chunk", chunk);formData.append("hash", fileHash);formData.append("index", index);// 替换为真实的上传URL,并根据需要实现onUploadProgressawait axios.post("上传URL", formData);},// 通知服务器合并切片notifyServerToMerge(fileHash) {// 通知服务器合并切片,应替换为真实的合并API调用console.log(`通知服务器将文件与哈希合并: ${fileHash}`);},},
};
</script>

效果:
Vue 大文件切片上传实现指南包会,含【并发上传切片,断点续传,服务器合并切片,计算文件MD5,上传进度显示,秒传】等功能

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

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

相关文章

(免费分享)基于微信小程序自助停取车收费系统

本项目的开发和制作主要采用Java语言编写&#xff0c;SpringBoot作为项目的后端开发框架&#xff0c;vue作为前端的快速开发框架&#xff0c;主要基于ES5的语法&#xff0c;客户端采用微信小程序作为开发。Mysql8.0作为数据库的持久化存储。 获取完整源码&#xff1a; 大家点赞…

上位机图像处理和嵌入式模块部署(qmacvisual并发执行)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 类似于qmacvisual这样的软件&#xff0c;其实价格并不便宜。比如大家熟知的halcon、vision pro、vision master这样的软件&#xff0c;最便宜的版本…

AlexNet网络模型

AlexNet 是一个深度卷积神经网络&#xff0c;由 Alex Krizhevsky、Ilya Sutskever 和 Geoffrey Hinton 在 2012 年的 ImageNet 大规模视觉识别挑战赛&#xff08;ILSVRC&#xff09;中首次提出并获得了显著的成功。它是深度学习历史上一个里程碑式的模型&#xff0c;对后来的深…

【漏洞复现】通天星CMSV6车载主动安全监控云平台inspect_file接口处存在任意文件上传漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

【opencv】教程代码 —features2D(4)利用两张摄像机拍摄的图片计算单应性矩阵...

homography_from_camera_displacement.cpp Chessboard poses 棋盘姿态 使用根据相机位移计算的单应性扭曲图像 使用根据绝对相机姿势计算的单应性扭曲图像 Warped images comparison 扭曲图像比较 左侧-nfindHomography 右侧-使用根据相机位移计算的单应性扭曲图像 终端输出&a…

Electron 打包自定义NSIS脚本为安装向导增加自定义页面增加输入框

Electron 打包工具有很多&#xff0c;如Electron-build、 Electron Forge 等&#xff0c;这里使用Electron-build&#xff0c;而Electron-build使用了nsis组件来创建安装向导&#xff0c;默认情况nsis安装向导不能自定义安装向导界面&#xff0c;但是nsis提供了nsis脚本可以扩展…

Express框架搭建项目 node.js

文章目录 引言Express框架介绍express安装环境准备写一个简单的项目展示 文章总结 引言 Express是一个基于Node.js平台的轻量级Web应用框架&#xff0c;它提供了简洁的API和丰富的功能&#xff0c;使得开发者能够快速地构建Web服务器和API。本文将带领大家从零开始&#xff0c…

企业管理新思考:利润率与质量在创业路上的重要性

一、引言 在当下这个充满变革与挑战的商业环境中&#xff0c;创业者和企业家们时常面临着规模扩张与利润增长之间的权衡。著名天使投资人吴世春先生的一席话&#xff0c;为我们指明了方向&#xff1a;“做企业利润率优先于规模&#xff0c;质量优先于数量。”这一深刻见解&…

unity 使用Base64编码工具对xml json 或者其他文本进行加密 解密

Base64编码加密解密工具 这是一个加密解密的网页工具&#xff0c;别人可以把他加密后的字符串给你&#xff0c;然后你可以用代码解密出来&#xff0c; 或者自己对内容进行加密&#xff0c;解密处理。 /// <summary>/// Base64 解码/// </summary>string DecodeBase…

【WEEK6】 【DAY3】MySQL函数【中文版】

2024.4.3 Wednesday 目录 5.MySQL函数5.1.常用函数5.1.1.数据函数5.1.2.字符串函数5.1.2.1.CHAR_LENGTH(str)计算字符串str长度5.1.2.2.CONCAT(str1,str2,...)拼接字符串str1 str2 ...5.1.2.3.INSERT(str,pos,len,newstr)把原文str第pos位开始长度为len的字符串替换成newstr5.…

WPF上使用MaterialDesign框架---下载与配置

一、介绍&#xff1a; Material Design语言的一些重要功能包括 系统字体Roboto的升级版本 &#xff0c;同时颜色更鲜艳&#xff0c;动画效果更突出。杜拉特还简要谈到了新框架的一些变化。谷歌的想法是让谷歌平台上的开发者掌握这个新框架&#xff0c;从而让所有应用就有统一的…

DETR【Transformer+目标检测】

End-to-End Object Detection with Transformers 2024 NVIDIA GTC&#xff0c;发布了地表最强的GPU B200&#xff0c;同时&#xff0c;黄仁勋对谈《Attention is All You Need》论文其中的7位作者&#xff0c;座谈的目的无非就是诉说&#xff0c;Transformer才是今天人工智能成…

技术揭秘:如何打造完美互动的充电桩硬件与服务平台?

充电桩平台全套源码地址 https://gitee.com/chouleng/cdzkjjh.git 这张图像是一个系统或服务的架构图。以下是对图中各个部分的描述&#xff1a; 前端&#xff1a; 位于图像的顶部&#xff0c;颜色为浅绿色。用户服务端&#xff1a; 紧邻前端&#xff0c;颜色为淡黄色。设备服…

基于深度学习的肿瘤图像检测系统(网页版+YOLOv8/v7/v6/v5代码+训练数据集)

摘要&#xff1a;在本博客中&#xff0c;我们深入探讨了基于YOLOv8/v7/v6/v5的肿瘤图像检测系统。核心上&#xff0c;我们采用了最新的YOLOv8技术&#xff0c;并将其与YOLOv7、YOLOv6、YOLOv5算法进行了综合整合和性能指标对比分析。我们详细阐述了当前国内外在此领域的研究现状…

个人医疗开支预测项目

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 项目背景 随着医疗成本的持续上涨&#xff0c;个人医疗开支成为一个重要议题。理解影响医疗费用的多种因素对于医疗保险公司、政府机构以及个人…

Java零基础入门-java8新特性(下篇)

一、概述 ​上几期&#xff0c;我们是完整的学完了java异常类的学习及实战演示、以及学习了线程进程等基础概念&#xff0c;而这一期&#xff0c;我们要来玩点好的东西&#xff0c;那就是java8&#xff0c;我们都知道java8是自2004年发布java5之后最重要且一次重大的版本更新&…

Mac OS上使用matplotlib库显示中文字体

文章目录 问题描述解决步骤参考文章 问题描述 如果我们想要使用matplotlib画图的话&#xff0c;可能会出现下面的这种warning: UserWarning: Glyph 24212 (\N{CJK UNIFIED IDEOGRAPH-5E94}) missing from current font.解决步骤 解决这个问题&#xff0c;可以按照下面的做法…

SpringBoot全局异常处理

问题 当我们没有做任何的异常处理时&#xff0c;我们三层架构处理异常的方案&#xff1a; Mapper接口在操作数据库的时候出错了&#xff0c;此时异常会往上抛(谁调用Mapper就抛给谁)&#xff0c;会抛给service。 service 中也存在异常了&#xff0c;会抛给controller。 而在…

Python基于深度学习的人脸识别项目源码+演示视频,利用OpenCV进行人脸检测与识别 preview

​ 一、原理介绍 该人脸识别实例是一个基于深度学习和计算机视觉技术的应用&#xff0c;主要利用OpenCV和Python作为开发工具。系统采用了一系列算法和技术&#xff0c;其中包括以下几个关键步骤&#xff1a; 图像预处理&#xff1a;首先&#xff0c;对输入图像进行预处理&am…

鸿蒙南向开发案例:【智能养花机】

样例简介 智能养花机通过感知花卉、盆栽等植宠生长环境的温度、湿度信息&#xff0c;适时为它们补充水分。在连接网络后&#xff0c;配合数字管家应用&#xff0c;用户可远程进行浇水操作。用户还可在应用中设定日程&#xff0c;有计划的按日、按周进行浇水。在日程中用户可添…