切片上传记录

核心就是

1 前端分片

2 后端组装

3 md5校验

Spark-md5介绍

用md5就是为了防止文件被篡改,小的文件直接可以用整个文件传入,返回文件md5,但是越大的文件(超过2G),如果用整文件的方式,时间会很久,分片计算md5会节约时间;另外MD5算法是一个单向哈希函数,不可逆的。

官网介绍:spark-md5

官网demo

来分析下官网的例子

javascript 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>incremental md5</title>
		<style>
			body{text-align:center;font:13px Tahoma}
			form{margin:9vh auto}
			pre{background:#ffd;border:1px solid orange;padding:1em;margin:0 auto;display:none;text-align:left;line-height:1.25}
		</style>
	</head>
	<body>
		<h1>incremental md5 demo</h1>
		<h3>with <a target="_blank" href="//github.com/satazor/SparkMD5">SparkMD5</a></h3>
		<form method="POST" enctype="multipart/form-data" onsubmit="return false;" ><input id=file type=file placeholder="select a file" /></form>
		<pre id=log></pre>
		<script src="//cdn.rawgit.com/satazor/SparkMD5/master/spark-md5.min.js"></script>
		<script>
			var log=document.getElementById("log");
			document.getElementById("file").addEventListener("change", function() {
				var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
					file = this.files[0],
					chunkSize = 2097152, // read in chunks of 2MB
					chunks = Math.ceil(file.size / chunkSize), // 要分成几片
					currentChunk = 0,
					spark = new SparkMD5.ArrayBuffer(), // 初始化MD5实例
					frOnload = function(e){
						log.innerHTML+="\nread chunk number "+parseInt(currentChunk+1)+" of "+chunks;
						spark.append(e.target.result); // append array buffer 追加缓冲
						currentChunk++;
						if (currentChunk < chunks)
							loadNext();
						else
						   log.innerHTML+="\nfinished loading :)\n\ncomputed hash:\n"+spark.end()+"\n\nyou can select another file now!\n"; // 结束
					},
					frOnerror = function () {
						log.innerHTML+="\noops, something went wrong.";
					};
				function loadNext() {
					var fileReader = new FileReader();
					fileReader.onload = frOnload;
					fileReader.onerror = frOnerror;
					var start = currentChunk * chunkSize,
						end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
					fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
				};
				log.style.display="inline-block";
				log.innerHTML="file name: "+file.name+" ("+file.size.toString().replace(/\B(?=(?:\d{3})+(?!\d))/g, ',')+" bytes)\n";
				loadNext();
			});
		</script>
	</body>
</html>

核心的就是这三个:

spark = new SparkMD5.ArrayBuffer(),

spark.append()

spark.end()

前端实现

前端要怎么分块,核心代码,chunkSize有高手建议不要超过5M,计算出起始和结束的字节数,用

File.prototype.slice来截取

javascript 复制代码
 const start = currentChunk * chunkSize;
 const end = start + chunkSize >= file.size ? file.size : start + chunkSize;
 const blobSlice = File.prototype.slice;
 const blob = blobSlice.call(file, start, end);

然后把这一部分的blob算出切片的md5,一并发给后端后发送merge请求

后端实现

上传接口

包括切片的index,切片的md5,文件名称

如果当前分片文件不存在,则存储

javascript 复制代码
import * as fse from "fs-extra";
const outStream = fse.createWriteStream(chunkPath);
const inStream = Readable.from(file.stream ?? file.buffer); //blob
inStream.pipe(outStream);

merge

合并文件

javascript 复制代码
// 分片循环
const buffer = await fse.readFile(chunkPath);
await fse.appendFile(finalPath, buffer);

剩余的一些问题

1 上传过程中,如果刷新页面,或者网络问题,断点续传的考虑, 需要后端存储切片信息,发给前端已有切片index,前端再重新继续切片请求

2 校验已有文件,无需重传

相关推荐
GISer_Jing16 分钟前
[总结篇]个人网站
前端·javascript
疯狂的沙粒37 分钟前
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
前端·uni-app·html
小妖66641 分钟前
html 滚动条滚动过快会留下边框线
前端·html
heroboyluck1 小时前
Svelte 核心语法详解:Vue/React 开发者如何快速上手?
前端·svelte
海的诗篇_1 小时前
前端开发面试题总结-JavaScript篇(二)
开发语言·前端·javascript·typescript
琹箐1 小时前
ant-design4.xx实现数字输入框; 某些输入法数字需要连续输入两次才显示
前端·javascript·anti-design-vue
程序员-小李1 小时前
VuePress完美整合Toast消息提示
前端·javascript·vue.js
Uyker2 小时前
从零开始制作小程序简单概述
前端·微信小程序·小程序
EndingCoder6 小时前
React从基础入门到高级实战:React 实战项目 - 项目三:实时聊天应用
前端·react.js·架构·前端框架
阿阳微客7 小时前
Steam 搬砖项目深度拆解:从抵触到真香的转型之路
前端·笔记·学习·游戏