大文件上传之分片上传和断点续传

423 阅读1分钟

分片上传

把文件分成若干份,这若干份同时向服务器上传,等全部上传成功后,再把这若干份文件组合成一个大文件

核心代码如下:

// 创建切片
function createChunk(file, size = 2 * 1024 * 1024) {//两个形参:file是大文件,size是切片的大小
    const chunkList = []
    let cur = 0
    while (cur < file.size) {
        chunkList.push({
                file: file.slice(cur, cur + size)//使用slice()进行切片
        })
        cur += size
    }
    return chunkList
}
//注意调用位置,不是在全局,而是在读取文件的回调里调用
chunkList = createChunk(files)
console.log(chunkList);
//数据处理
async function uploadFile(list) {
    const requestList = list.map(({file,fileName,index,chunkName}) => {
        const formData = new FormData() // 创建表单类型数据
        formData.append('file', file)//该文件
        formData.append('fileName', fileName)//文件名
        formData.append('chunkName', chunkName)//切片名
        return {formData,index}
    }).map(({formData,index}) =>axiosRequest({
        method: 'post',
        url: 'http://localhost:3000/upload',//请求接口,要与后端一一一对应
        data: formData
    }).then(res => {
      console.log(res); 
      //显示每个切片上传进度
      let p = document.createElement('p')
      p.innerHTML = `${list[index].chunkName}--${res.data.message}`
      document.getElementById('progress').appendChild(p)
    })
  )
  await Promise.all(requestList)//保证所有的切片都已经传输完毕
}
//请求函数
function axiosRequest({method = "post",url,data}) {
    return new Promise((resolve, reject) => {
        const config = {//设置请求头
            headers: 'Content-Type:application/x-www-form-urlencoded',
        }
        //默认是post请求,可更改
        axios[method](url,data,config).then((res) => {
            resolve(res)
        })
    })
}
// 文件上传
upload.addEventListener('click', () => {
    const uploadList = chunkList.map(({file}, index) => ({
        file,
        size: file.size,
        percent: 0,
        chunkName: `${files.name}-${index}`,
        fileName: files.name,
        index
    }))
    //发请求,调用函数
    uploadFile(uploadList)
})

断点续传

在分片上传的基础上,再次上传时,检测已经上传过的切片,如已上传,不再重复上传

分三步进行

  1. 为每个分段生成 hash 值,使用 spark-md5 库
  2. 将上传成功的分段信息保存到本地
  3. 重新上传时,进行和本地分段 hash 值的对比,如果相同的话则跳过,继续下一个分段的上传