大文件上传
# 大文件上传满足条件
- 支持拆分上传请求(即切片上传)
- 支持断点续传
- 支持显示上传进度和暂停上传
# 大文件上传解决方案
- vue-simple-uploader 组件
vue-simple-uploader 是基于 simple-uploader.js 封装的 vue 上传插件
安装:
npm install vue-simple-uploader --save
教程地址:https://www.cnblogs.com/xiahj/p/vue-simple-uploader.html (opens new window)
# 切片上传
编码方式上传中,在前端我们只要先获取文件的二进制内容,然后对其内容进行拆分,最后将每个切片上传到服务端即可。
在 JavaScript 中,文件 FIle 对象是 Blob 对象的子类,Blob 对象包含一个重要的方法 slice,通过这个方法,我们就可以对二进制文件进行拆分。
实现步骤
把大文件进行分段(循环分解文件,依次创建文件切片) 比如 2M,发送到服务器携带一个标志,暂时用当前的时间戳,用于标识一个完整的文件
服务端保存各段文件
浏览器端所有分片上传完成,发送给服务端一个合并文件的请求
服务端根据文件标识、类型、各分片顺序进行文件合并
删除分片文件
切片方案:
按数量:不管上传文件的大小,切成固定的块数,然后上传。
按大小:不管上传文件的大小,每次切的块大小相同,然后上传。
第一种方法的缺点就是,如果文件过小的话,切成固定的块数,明显浪费 HTPP 请求,如果文件过大,切成固定的块数,切的每块可能依然过大,即切片的切片还需要继续切片。所以使用这种方法,需要加上限定条件,假如上传文件的大小为 s,限定条件应该这样写 n <= s <= m。
第二种方法的缺点就是,如何确定每次上传文件的大小,定小了,容易出现 HTTP 请求过多,定大了,容易出现切片效果不理想,切片的大小真是让人头疼。
相对优化的方案(两种结合):
- 文件过小,不用切片,可以直接上传。例如 10kb、190kb、200kb、甚至 1M……。
- 文件三四十兆的这种,就固定切片大小就好。
- 大于一百兆但是小于 1G 的这种,可以分区间,不同的区间给不同固定的分包数量。
- 如果文件再大,可以两者方法结合用,先固定分包数量,然后随机包大小。
- 文件超大的那种,应该寻求并行上传方法,简单点前端可以直接禁止上传超大文件。
# 断点续传
断点续传:可以从已经上传部分开始继续上传未完成的部分,而没有必要从头开始上传,节省上传时间。
解决了大文件上传超时和服务器的限制
实现方案:
- 为每个切片生成 hash 值,使用 spark-md5 库
- 在切片上传成功后,保存已上传的切片信息(前端:locaStorage,后端:接口保存,查询)
- 重新上传时,遍历切片列表,进行和本地分段 hash 值的对比,如果相同的话则跳过,继续下一个分段的上传(只选择未上传的切片进行上传,)
- 所有切片上传完毕后,再调用 mkfile 接口通知服务端进行文件合并
问题:切片过期
# 秒传
原理:计算整个文件的 HASH,在执行上传操作前,向服务端发送请求,传递 MD5 值,后端进行文件检索。若服务器中已存在该文件,便不进行后续的任何操作,上传也便直接结束。
问题:不想秒传,怎么操作?
要不秒传,其实只要让 MD5 改变,就是对文件本身做一下修改(改名字不行),例如一个文本文件,你多加几个字,MD5 就变了,就不会秒传了.
# 上传进度和暂停
通过 xhr.upload 中的 progress 方法可以实现监控每一个切片上传进度。
上传暂停的实现也比较简单,通过 xhr.abort 可以取消当前未完成上传切片的上传,实现上传暂停的效果,恢复上传就跟断点续传类似,先获取已上传的切片列表,然后重新发送未上传的切片。
# Hash 计算
秒传,需要通过 MD5 值判断文件是否已存在。
续传:需要用到 MD5 作为 key 值,当唯一值使用。
# 大文件上传问题汇总
切片上传失败怎么办
上传过程中刷新页面怎么办
如何进行并行上传
切片什么时候按数量切,什么时候按大小切
如何结合 Web Worker 处理大文件上传
如何实现秒传