大文件上传实践后总结

135 阅读3分钟

原理探索: 主要是借助于File.prototype.slice() 方法,根据设定的阈值,来将这个文件的二进制内容,切片成一个个的小文件slice。然后并行上传这些切片,最后判断切片是否传递完毕,之后进行合并解压操作!!!

核心问题: -秒传,其实就是上传之前发的get请求做的事,判断是否数据库存在已经完全上传完成的同名文件,是的话,直接返回一个skip标识,表示直接提示上传成功

  • 断点续传

    -其实就是服务器发现该文件上传过分片信息, 我跟后端当时设计就是,我这边在上传的时候会发两个upload请求,一个get请求,一个post请求,get用于询问服务器已经上传过过哪些分片了,以及是否秒传,会出现:a.如果是一个已经完整上传的文件,直接skip,然后返回该文件的url。 b. 后台返回了的uploaded:[] ,里面是已经上传过的分片的index 默认从1开始,然后再发送upload的 post请求前比较,已经上传的就会直接跳过,直到找到没有上传过的,继续上传。

  • 显示上传进度

image.png -

  • 如何切片:

      1. 获取到文件对象后,借助于spark-md5 这个库,在上传之前(一般的文件uploader 都会有上传前的回调),调用一个function 比如 generateMD5(file,{}),里面实例化一个fileReader,定义好chunkSize,也就是分片的大小,chunks = math.ceil(file.size / chunkSize),currentChunk = 0 generateMD5里面定义一个loadNext函数,实例化一个spark的数组缓冲池 new SparkMD5.arrayBuffer() 开始调用一次,在里面使用fileReader.readAsArrayBuffer(File.prototype.slice(file.file,start, end)),开始 start=0 end=start=chunksize , 得到一个blob, 读取该blob,会触发fileReader.onload(),, onload里面继续调用loadNext() 函数,onload执行一次,currentChunk++,就达到循环切片至最后一个chunk,依次读取chunk并且通过spark.append(将读取到的blob内容) 最后 spark。end(),生成一个唯一hash, 这样就为每一个切片生成了一个唯一的hash。 当然每一个切片都需要与其源文件有一个多对一的关系,也就是这些切片都需要一个唯一的源文件id[一般文件名拼一个Uid],,用于表示是某一个文件的所有切片。
  • 如何保证所有的切片完好,在组合解压

    • 一般两种的方式

      • 上传的时候,传入totoalChunks,以及每个片的顺序,比如total100, 然后后端接收完毕之后,通过hash去统计,是否 === totalChunk, 等于的话后端直接按照chunk的顺序以及大小进行合并。这种方式就有缺点,可能前端提示上传成功,但是可能后端还再合并。 导致去看的时候,看不到文件。
      • 第二种,前面都差不多,不同在于,后端会在最后一个片上传后,检验所有的切片都接受完毕。就返回一个isMerge字段给前端,前端在根据这个字段去主动发起一个合并请求。等合并完成,前端在提示解压上传成功。就可以解决上述问题