8.大文件上传

1. 背景

在项目中会有各种的上传场景,可以能图片,可能是视频,通常大于200m的就属于大文件了

经常会遇到一些问题:

  1. 网络断开之后,之前传的没了
  2. 传着传着,网络波动了,结果啥都没了
  3. 关机了,想接着穿,做不到

这些场景对应的解决方法有:

  1. 断点续传
  2. 断开重连重连
  3. 切片上传

2. 方案

一般的实现方案

  • 前端切片,chunk 比如说1g的文件我们取要切分为500k一个片,那就是1000*1024/500这么多片
  • 将切片传递给后端,切得片要取名,一般使用hash作为名字,并且还需要下标作为顺序进行传递给后端
  • 后端组合切片,看看有没有少了一些,有没有重复的,如果是对的,最终合到一起就变成用户上传的文件了

缺点:

  • 这么多切片肯定会卡,所以我们会使用web-worker多线程进行切片,处理完之后交给主进程发送给后端

  • 切换后,用户关闭浏览器后,我们需要将数据存储在IndexDB,下次用户进来之后,嗅探一下是否存在未完成上传的切片,就有尝试继续上传

  • websocket:实时通知,和请求序列的控制

  • 整体说一说主要大文件上传器整体设计

    • 组件设计

    • props、事件、状态

    • 拖拽上传、多文件选择

    • 文件夹上传

    • 通用不同文件的上传、统一上传协议

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
  </head>
  <body>
    <input type="text" id="fileInput" />
    <button onclick="uploadFile()">Upload</button>
    <script>
      const CHUNK_SIZE = 5 * 1024 * 1024; // 每一块为5m
      function uploadFile() {
        const file = document.getElementById("fileInput")[0];
        if (!file) {
          alert("please select a file");
          return;
        }
        const totalChunk = Math.ceil(file.size / CHUNK_SIZE);
        let currentChunk = 0;
        function uoloadChunk() {
          if (currentChunk >= totalChunk) {
            alert('upload complete')
            return;
          }

          const start=currentChunk*CHUNK_SIZE
          const end=Math.min(start + CHUNK_SIZE,file.size)

          const chunk=file.slice(start,end)

          const formData=new FormData()
          formData.append('file',chunk)
          formData.append('chunkNumber',currentChunk+1)
          formData.append('totalCHunks',totalChunk)

          fetch('/upload',{
            method:'POST',
            body:formData
          }).then(response=>{
            if(response.ok){
              currentChunk++
              uploadChunk()
            }else{
              console.log('chunk upload failed')
            }
          }).catch(error=>{
            console.log('upload error',error)
          })
        }
        uploadChunk()
      }
    </script>
  </body>
</html>
ON THIS PAGE