“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情”
日常开发过程中,经常会遇到需要上传文件的问题,有时候文件会特别的大,这时候需要考虑文件秒传,文件分片上传。 以此来实现高效上传,提升用户体验。本文主要介绍文件秒传。
文件秒传原理
文件秒传的原理是在前端上传文件之前,拿到文件,并计算文件的MD5值,请求接口将MD5传递给后端,后端查询数据库是否存在相同的MD5值,如果存在,则直接返回对应的文件ID, 如果不存在,则返回空。
前端在收到响应后,如果文件id存在,则直接停止上传,将上传结果置为成功(秒传成功)。如果不存在,则走后续分片上传的流程。
常用组件
秒传关键在于计算文件MD5值,前端计算文件MD5值的常用工具为 spark-md5 它能够非常快速的计算大文件的MD5值, 满足开发需求。
函数封装
考虑到代码公用性,将此特抽出一个公用方法。 如下: 详见代码及注释。
import SparkMD5 from 'spark-md5';
/**
* 计算文件Md5
* 将文件分片逐步计算最终合并得出整个文件md5, 提升计算速度
* @param {*} file
*/
export default function computeFileMD5(file) {
return new Promise((resolve, reject) => {
let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
let chunkSize = 2097152; // 按照一片 2MB 分片
let chunks = Math.ceil(file.size / chunkSize); // 片数
let currentChunk = 0;
let spark = new SparkMD5.ArrayBuffer();
let fileReader = new FileReader();
fileReader.onload = function (e) {
console.log('read chunk nr', currentChunk + 1, 'of', chunks);
spark.append(e.target.result);
currentChunk++;
if (currentChunk < chunks) {
loadNext();
} else {
console.log('finished loading');
let md5 = spark.end(); //最终md5值
spark.destroy(); //释放缓存
resolve(md5);
}
};
fileReader.onerror = function (e) {
console.warn('oops, something went wrong.');
reject(e);
};
function loadNext() {
let start = currentChunk * chunkSize,
let end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
}
loadNext();
})
}
函数的调用
函数调用一般在文件上传前置函数,注意异步
async fileAdd(file) {
// 注意此处file, file || file.file
let md5 = await computeFileMD5(file.file);
console.log(md5);
// 调用接口实现秒传逻辑
}
总结
本文介绍了文件秒传的原理以及实现思路,其中对关键步骤获取md5做出了详细说明,以及示例了对应函数的封装和调用。希望可以帮助给有相关需求的人一些思路。