You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// 部分代码展示
let spark = new SparkMD5.ArrayBuffer();
let fileReader = new FileReader();
fileReader.onload = e => {
if (e.target && e.target.result) {
count++;
spark.append(e.target.result as ArrayBuffer);
}
if (count < totalCount) {
loadNext();
} else {
resolve(spark.end());
}
};
function loadNext() {
fileReader.readAsArrayBuffer(fileChunkList[count].file);
}
loadNext();
基本流程
前端通过input获取到用户选择的文件,放入FormData中,设置 content-type 为 multipart/form-data发送给服务端。服务端通过cookie/token/...等等信息,再对文件/数据库进行处理操作。
大文件上传
大文件上传,可能会出现,上传时间过长,接口限制了文件大小。所以,大文件直接上传,也很不友好,一般采用分片上传的方式去上传。而blob提供了slice方法, file继承了blob自然也能使用slice去进行分片处理。
处理流程:
服务端的话,我这边是把文件根据对应的hash和下标进行命名,即static/hash/hash-i。利用fs.rename去修改文件&路径, 通过pipe合并文件。
分片上传的思路如下:
第一步:先对文件进行MD5的加密, 这样有两个好处, 即可以对文件进行唯一的标识, 为秒传做准备, 也可以为后台进行文件完整性的校验进行比对
第二步:拿到MD5值以后, 要查询一下, 这个文件是否已经上传过了, 如果上传过了, 就不用再次重复上传, 也就是能够秒传, 网盘里的秒传, 原理也是一样的
第三步:对文件进行切片, 假如文件是500M, 一个切片大小我们定义为50M, 那么整个文件就为分为100次上传
第四步:向后台请求一个接口, 接口里面的数据是该文件已经上传过的文件块, 为什么要有这个请求呢? 我们经常用网盘, 网盘里面有续传的功能, 一个文件传到一半, 由于各种原因, 不想再传了, 那么再次上传的时候, 服务器应该保留我之前上传过的文件块, 跳过这些已经上传过的块, 再次上传其他文件块, 当然续传方案有很多, 目前来看, 单独发一次请求, 这样效率最高
第五步:开始对未上传过的块进行POST上传
第六步:当上传成功后, 通知服务器进行文件的合并, 至此, 上传完成!
断点续传实现原理
断点续传就是在上传一个文件的时候可以暂停掉上传中的文件,然后恢复上传时不需要重新上传整个文件。
该功能实现流程是先把上传的文件进行切割,然后把切割之后的文件块发送到服务端,发送完毕之后通知服务端组合文件块。
其中暂停上传功能就是前端取消掉文件块的上传请求,恢复上传则是把未上传的文件块重新上传。需要前后端配合完成。
切割文件:这个功能点在整个断点续传中属于比较重要的一环,这里仔细说明下。我们用ajax上传一个大文件用的时间会比较长,在上传途中如果取消掉请求,那在下一次上传时又要重新上传整个文件。而通过把大文件分解成若干个文件块去上传,这样在上传中取消请求,已经上传的文件块会保存到服务端,下一次上传就只需要上传其他没上传成功的文件块(不用传整个文件)。
这里把文件块放入一个fileChunkList数组,方便后面去获取文件的MD5值、上传文件块等。
获取文件MD5值:我们不能通过文件名来判断服务端是否存在上传的文件,因为用户上传的文件很可能会有重名的情况。所以应该通过文件内容来区分,这样就需要获取文件的MD5值。
使用spark-md5模块获取文件的MD5值。模块详情点击这里
上传切割后的文件块:根据前面的fileChunkList数组,使用FormData上传文件块。
合并文件:就是等所有文件块上传成功后发送ajax通知服务端,让服务端把文件块进行合并。
暂停功能:把上传文件块的请求放到一个数组里,请求完成的则从数组中删除;点击暂停的时候把数组里所有的请求暂停。
断点续传
大文件分片上传,如果客户端发生异常中断了上传过程,那么下次重新上传的时候,比较友好的做法应该是跳过那些已经上传的片段。
那么问题也就是,怎么跳过那些文件?刚才前面的代码,也显示了,其实就是通过${hash}-${i}设置文件名,然后保存已经上传成功的片段数据,在文件分片上传的时候,跳过已经上传过的片段,就是断点续传辽。
对于这类数据存储,一般都是两个方法:
前端存储的话,一般就是用localStorage,不太推荐使用。因为用户如果清了缓存,或者换了设备登陆,就无法生效。
服务端的话,就返回对应的已成功上传的片段名。因为对应userId下的文件hash-i,是唯一的。node这里就采用readdirSync/readdir去读取文件名辽。
WebWoker获取hash
去获取文件的hash。推荐使用spark-md5去生成文件的hash。因为生成hash过程是比较耗时间的,我这边采用了webworker去计算hash。
webworker我这边是直接是将webworker的代码写到html上面,然后利用Blob & URL.createObjectURL去本地创建webwoker
拖拽上传
拖拽上传就是利用onDrop和onDragOver,阻止浏览器默认事件,然后就得到对应文件
文件下载
form表单呀,open呀,直接a标签呀,blob方式呀等等。我这边采用的是利用blob去下载文件,主要考虑到,可以进行鉴权操作&可以下载各种类型文件等等。
过程就是
进度条
进度条就是ProgressEvent,如果是断点续传,就先对片段进行遍历判断是否有已经上传过的,然后就得到一个初始进度。
The text was updated successfully, but these errors were encountered: