基于Vue3.0 Node.js 的 大文件切片上传、秒传、断点续传实现方案梳理

✨💻 在处理大文件上传时,切片上传是提高效率与用户体验的关键技术之一。下面将详细介绍如何在前端利用Vue框架与Node.js后端配合,实现这一功能。

👆🏻大体流程

在这里插入图片描述

👆🏻一、文件切片上传

  1. 通过文件选择器获取用户选择文件
<template>
  <div>
   	<input label="选择附件" type="file" @change="handleFileChange" />
	<div @click="handleUpload">上传附件</div>
 </div>
</template>
<script>
     handleFileChange(e) {
     	this.container.file = e.target.files;
	 }
</script>
  1. 设定分片大小,将文件切片成多个文件块
<script>
	const SIZE = 10 * 1024 * 1024; // 切片大小
	// 生成文件切片
	createFileChunk(file, size = SIZE) {
	 const fileChunkList = [];
	  let cur = 0;
	  while (cur < file.size) {
	    fileChunkList.push({ file: file.slice(cur, cur + size) });
	    cur += size;
	  }
	  return fileChunkList;
	},
</script>
  1. 通过 spark-md5插件以及借助 web-worker 来并行生成文件的唯一Hash标识
<script>
//入参:fileChunkList ,对应 的文件切片数组
calculateHash(fileChunkList) {
     return new Promise(resolve => {
       this.container.worker = new Worker("/hash.js");
	   //将 fileChunkList 通过 postMessage 发送给 web-worker
       this.container.worker.postMessage({ fileChunkList });
	   //接收 web-worker 返回的消息
       this.container.worker.onmessage = e => {
         const { hash } = e.data;
         if (hash) {
           resolve(hash);
         }
       };
     });
   }
</script>

工具函数 hash.js
// 导入脚本
 self.importScripts("/spark-md5.min.js");
// 生成文件 hash 代码
self.onmessage = e => {
  const { fileChunkList } = e.data;
  const spark = new self.SparkMD5.ArrayBuffer();
  let count = 0;
  const loadNext = index => {
    const reader = new FileReader();
    reader.readAsArrayBuffer(fileChunkList[index].file);
    reader.onload = e => {
      count++;
      spark.append(e.target.result);
      if (count === fileChunkList.length) {
        self.postMessage({
          hash: spark.end()
        });
        self.close();
      }
      // 递归计算下一个切片
      loadNext(count);
    };
  };
  loadNext(0);
};
  1. 点击上传附件按钮 开始对大文件进行切片
// 调用后端接口上传切片
async uploadChunks() {
	 const requestList = this.data
	    .map(({ chunk,hash }) => {
	      const formData = new FormData();
	      formData.append("chunk", chunk);
	      formData.append("hash", hash);
	      formData.append("filehash", this.container.hash);
	      return { formData };
	    })
	    .map(async ({ formData }) =>
		//发起后端请求
	      axios.post({
	        url: "XXXXXXXX",
	        data: formData
	      })
	 );
	 await Promise.all(requestList); // 并发请求后端api
}

const async handleUpload() {
	if (!this.container.file) return;
	const fileChunkList = this.createFileChunk(this.container.file);
	this.container.hash = await this.calculateHash(fileChunkList);
	this.data = fileChunkList.map(({ file },index) => ({
	    chunk: file,
	    hash: this.container.hash + "-" + index // hash + 数组下标
	}));
	await this.uploadChunks();
}

👆🏻二、文件秒传

第一步:和文件切片前几步骤相同,先获取 改文件对应的文件切片 以及 hash 值

第二步:调用后端接口查询已经成功上传的文件hash值,如果都已经上传过该文件,前端显示上传完成

👆🏻 三、断点续传

第一步:和文件切片前几步骤相同,先获取 改文件对应的文件切片 以及 hash 值

第二步:调用后端接口查询已经成功上传的文件hash值,前端将已经上传过的hash值过滤得到未上传的文件hash值

第三步:将未上传的文件hash值列表,调用上传接口上传

👆🏻四、关于后端实现(Node版)

  1. 接收切片
const http = require("http");
const path = require("path");
const fse = require("fs-extra");
const multiparty = require("multiparty");
const server = http.createServer();
const UPLOAD_DIR = path.resolve(__dirname, "..", "target"); // 大文件存储目录
server.on("request", async (req, res) => {
  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader("Access-Control-Allow-Headers", "*");
  if (req.method === "OPTIONS") {
    res.status = 200;
    res.end();
    return;
  }
  // 使用 multiparty 包处理前端传来的 FormData
  // 在 multiparty.parse 的回调中,files 参数保存了 FormData 中文件,fields 参数保存了 FormData 中非文件的字段
  const multipart = new multiparty.Form();
  multipart.parse(req, async (err, fields, files) => {
    if (err) {
      return;
    }
    const [chunk] = files.chunk;
    const [hash] = fields.hash;
    const [filehash] = fields.filehash;
    const chunkDir = path.resolve(UPLOAD_DIR, filehash);
   // 切片目录不存在,创建切片目录
    if (!fse.existsSync(chunkDir)) {
      await fse.mkdirs(chunkDir);
    }
    // fs-extra 专用方法,类似 fs.rename 并且跨平台
    // fs-extra 的 rename 方法 windows 平台会有权限问题
    await fse.move(chunk.path, `${chunkDir}/${hash}`);
    res.end("received file chunk");
  });
});
server.listen(3000, () => console.log("正在监听 3000 端口"));
  1. 合并切片
//通过readStream流读文件
const pipeStream = (path, writeStream) =>
 new Promise(resolve => {
   const readStream = fse.createReadStream(path);
   readStream.on("end", () => {
     fse.unlinkSync(path);
     resolve();
   });
   readStream.pipe(writeStream);
 });
//合并切片
const mergeFileChunk = async (filePath, filehash, size) => {
 const chunkDir = path.resolve(UPLOAD_DIR, filehash);
 const chunkPaths = await fse.readdir(chunkDir);
 // 根据切片下标进行排序
 // 否则直接读取目录的获得的顺序可能会错乱
 chunkPaths.sort((a, b) => a.split("-")[1] - b.split("-")[1]);
 await Promise.all(
   chunkPaths.map((chunkPath, index) =>
     pipeStream(
       path.resolve(chunkDir, chunkPath),
       // 指定位置创建可写流
       fse.createWriteStream(filePath, {
         start: index * size,
         end: (index + 1) * size
       })
     )
   )
 );
 fse.rmdirSync(chunkDir); // 合并后删除保存切片的目录
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HTML静态网页成品作业(HTML+CSS)——故宫介绍网页(4个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有4个页面。 二、作品演示 三、代…

ubuntu 22.04下利用webmin 搭建一个Wordpress 网站(2)

上次我们讲到第二部分&#xff0c;今天我们继续这一个话题 第三部分&#xff1a;利用webmin创建一个wordpress网站 1、在 Webmin 内安裝Apache 未使用的模块> Apache Webserver > 现在安装 会出现如下图所示的有关软件 刷新模快后 检查开机时要自动启动Apache 测…

TI毫米波雷达可以用串口调试助理来获取原始数据吗?

摘要&#xff1a;本文介绍一下如何使用普通的串口调试助理来读取到AWR1843毫米波雷达的数据的。 使用的硬件如下图所示。 软件就是普通的串口助理&#xff0c;我用的是SSCOM&#xff0c;其他串口助理也是可以的&#xff0c;核心作用其实就是发送一行行的指令而已。 操作方法&am…

HTML(18)——浮动

标准流 标准流也叫文档流&#xff0c;指的是标签在页面中默认的排布规则&#xff0c;例如&#xff1a;块元素独占一行&#xff0c;行内元素可以一行显示多个 浮动 作用&#xff1a;让块级元素水平排列 属性名&#xff1a;float 属性值 left&#xff1a;左对齐right&#…

Google trend搜索关键词

Google trend地址&#xff1a;https://trends.google.com/trends/?geoUS&hlzh-CN 1、具体的操作步骤如下&#xff1a; 2、Google trend搜索页面如下&#xff1a;

https://curl.trillworks.com不能用的解决方法

gitee源码:https://gitee.com/Project0ne/curlconverter 首先打开上面的链接 然后下载文件 下载文件到本地 然后安装node.js(Node.js official website.)不会的自行百度,这里不做过多赘述。 在curlconverter文件夹下面打开终端(在文件夹下面右键-在终端打开) 输入 npm…

昇思25天学习打卡营第1天|快速入门

一、简介&#xff1a; 本节通过MindSpore已经封装好的API&#xff0c;快速实现一个深度学习模型的数据集准备、训练评估&#xff0c;模型参数保存和加载&#xff0c;对新手朋友十分友好。这里非常感谢华为昇思团队在算力和代码方面的指导。 二、环境准备&#xff1a; 在开始…

C# 唯一性进程的方法封装(Winform/WPF通用)

C#唯一进程封装 C# 唯一性进程的方法封装 public class UniqueProcess{/// <summary>/// 焦点切换指定的窗口&#xff0c;并将其带到前台/// </summary>/// <param name"hWnd"></param>/// <param name"fAltTab"></para…

搜狐视频全自动工具

项目介绍&#xff1a; 首先我们要用自己的一个号&#xff0c;作为主号&#xff0c;主号上发作品&#xff0c;利用不实名的小号通过脚本自动去浏览视频 小号看视频的同时会出现搜狐官方强行插入的广告&#xff0c;从而获得收益 收益介绍&#xff1a; 小号看一个视频会出现3-…

DDS信号的发生器(验证篇)——FPGA学习笔记8

前言&#xff1a;第一部分详细讲解DDS核心框图&#xff0c;还请读者深入阅读第一部分&#xff0c;以便理解DDS核心思想 三刷小梅哥视频总结&#xff01; 小梅哥https://www.corecourse.com/lander 一、DDS简介 DDS&#xff08;Direct Digital Synthesizer&#xff09;即数字…

Scrivener v3 解锁版安装教程 (写作辅助软件)

前言 Scrivener&#xff0c;一个多功能的写作软件&#xff0c;被世界各地的作家广泛采用&#xff0c;从小说家到剧本家&#xff0c;再到非小说类作家和学术研究者&#xff0c;它的用户群跨越了广泛的领域&#xff0c;包括学生、法律专业人士、记者和翻译。这个软件非常注重用户…

Node.js版Selenium WebDriver教程

目录 介绍 导言 Selenium基础 环境设置 使用npm安装selenium-webdriver模块 配置和管理浏览器驱动器 下载火狐 下载安装 webDriver 第一个WebDriver脚本 介绍 导言 在当今数字化时代&#xff0c;Web应用程序的质量和性能至关重要。为了确保这些应用的可靠性&#xf…

UnityShader——基础篇之UnityShader基础

UnityShader基础 UnityShader概述 材质和UnityShader 总的来说&#xff0c;在Unity中需要配合使用材质(Material)和 Unity Shader 才能达到需要的效果&#xff0c;常见流程为&#xff1a; 创建一个材质创建一个 Unity Shader&#xff0c;并把它赋给上一步中创建的材质把材质…

qt基本窗口类(QWidget,QDialog,QMainWindow)

1.三个基本窗口类 1.1QWidget 所有窗口的基类 可以内嵌到其他窗口的内部&#xff0c;无边框 也可以作为独立窗口显示&#xff0c;有边框 1.2QDialog 继承于QWidget 对话框窗口类 不可以内嵌到其他窗口 有模态和非模态两种显示方式 1.3QMainWind 继承于QWidget 主窗口类 不可以…

SD卡无法读取?原因分析与数据恢复策略

一、SD卡无法读取的困境 SD卡作为便携式的存储介质&#xff0c;广泛应用于手机、相机、平板等多种电子设备中。然而&#xff0c;在使用过程中&#xff0c;我们可能会遭遇SD卡无法读取的困扰。当我们将SD卡插入设备时&#xff0c;设备无法识别SD卡&#xff0c;或者虽然识别了SD…

【调试笔记-20240619-Windows-Typescripts中类型不匹配的解决方法】

调试笔记-系列文章目录 调试笔记-20240619-Windows-Typescripts中类型不匹配的解决方法 文章目录 调试笔记-系列文章目录调试笔记-20240619-Windows-Typescripts中类型不匹配的解决方法 前言一、调试环境操作系统&#xff1a;Windows 10 专业版调试环境调试目标 二、调试步骤搜…

数据结构:小白专场:树的同构2程序框架、建树及同构判别

T1T2是之前提到的结构数组&#xff0c;是全局变量&#xff0c;作为参数传进去 调用Ismorphic这个函数判断R1R2是不是同构的 首先考虑如何构建BuidTree函数 输入数据的结构如左图 知道n之后&#xff0c;n不为0&#xff0c;循环&#xff0c;循环一次读入一行数据 为了处理方便…

FlowUs知识库践行“持续交付”“持续推广” 让内容创作者专注内容

FlowUs在推出订阅付费功能时&#xff0c;充分体现了软件工程领域中的持续交付&#xff08;Continuous Delivery, CD&#xff09;与持续部署&#xff08;Continuous Deployment, CD&#xff09;理念&#xff0c;将这一高效、敏捷的软件开发策略融入知识管理与变现平台之中&#…

如何实现外部编码器轴和虚轴电子齿轮比例随动(汇川AM400PLC)

1、如何添加虚轴可以参考下面文章链接: 如何添加虚轴(AM400PLC)-CSDN博客文章浏览阅读2次。EtherCAT运动控制总线启用的时候,选择EtherCAT总线任务周期。选择好后,选择点击添加。https://blog.csdn.net/m0_46143730/article/details/139898985?csdn_share_tail=%7B%22type…