<
>

大规格文件的上传优化思路详解

2020-05-13 21:58:09 来源:易采站长站 作者:王振洲

在开发过程中,收到这样一个问题反馈,在网站上传 100 MB 以上的文件经常失败,重试也要等老半天,这就难为需要上传大规格文件的用户了。那么应该怎么做才能快速上传,就算失败了再次发送也能从上次中断的地方继续上传呢?下文为你揭晓答案~

温馨提示:配合 Demo 源码一起阅读效果更佳

整体思路

第一步是结合项目背景,调研比较优化的解决方案。
文件上传失败是老生常谈的问题,常用方案是将一个大文件切片成多个小文件,并行请求接口进行上传,所有请求得到响应后,在服务器端合并所有的分片文件。当分片上传失败,可以在重新上传时进行判断,只上传上次失败的部分,减少用户的等待时间,缓解服务器压力。这就是分片上传文件。

大文件上传

那么如何实现大文件分片上传呢?

流程图如下:

分为以下步骤实现:

1. 文件 MD5 加密

MD5 是文件的唯一标识,可以利用文件的 MD5 查询文件的上传状态。

根据文件的修改时间、文件名称、最后修改时间等信息,通过 spark-md5 生成文件的 MD5。需要注意的是,大规格文件需要分片读取文件,将读取的文件内容添加到 spark-md5 的 hash 计算中,直到文件读取完毕,最后返回最终的 hash 码到 callback 回调函数里面。这里可以根据需要添加文件读取的进度条。

实现方法如下:

// 修改时间+文件名称+最后修改时间-->MD5
md5File (file) {
 return new Promise((resolve, reject) => {
 let blobSlice =
  File.prototype.slice ||
  File.prototype.mozSlice ||
  File.prototype.webkitSlice
 let chunkSize = file.size / 100
 let chunks = 100
 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) // Append array buffer
  currentChunk++
  if (currentChunk < chunks) {
  loadNext()
  } else {
  let cur = +new Date()
  console.log('finished loading')
  // alert(spark.end() + '---' + (cur - pre)); // Compute hash
  let result = spark.end()
  resolve(result)
  }
 }
 fileReader.onerror = function (err) {
  console.warn('oops, something went wrong.')
  reject(err)
 }
 function loadNext () {
  let start = currentChunk * chunkSize
  let end =
  start + chunkSize >= file.size ? file.size : start + chunkSize
  fileReader.readAsArrayBuffer(blobSlice.call(file, start, end))
 }
 loadNext()
 })
}

2. 查询文件状态

前端得到文件的 MD5 后,从后台查询是否存在名称为 MD5 的文件夹,如果存在,列出文件夹下所有文件,得到已上传的切片列表,如果不存在,则已上传的切片列表为空。

暂时禁止评论

微信扫一扫

易采站长站微信账号