前端大文件上传分片上传

39 阅读2分钟

问题背景:

一般正常来说,文件的上传就普通的调用接口,拿到返回值就行, 但是这次的需求可能是要上传的文件比较大(视频文件最大可上传2个g)。好吧,先还是用普通的接口来进行调用,像这么大的文件上传起来先设置较长的超时时间。,说是可能一个小时都有可能。然后nginx那边也有代理,也需要去设置超时时间。好吧,以这种方式尝试着,大文件上传着上传着,莫名其妙会出现奇奇怪怪的各种问题,后端说是每次问题都不一样。好吧,那可能需要换一种上传方式来。要么换成websocket长连接,要么还是分片上传。当我还在看websocket的时候,后端又说分片上传已经写好了,很好,我的后端yyds! 每次都直接高效的作出最佳选择。那就是下面前端的上传方式了,也没什么好说的,直接看一下代码实现吧。

代码实现:

  async function handleUpload(file: any, func) {
    if (Typer.isNull(file)) {
      return message.error('未获取到文件')
      // return logger.error("未获取到文件");
    }
    // const fileList = e.target.files as FileList;
    // const file: File = fileList[0];
    // 文件属性大小判断处理-随便写的
    if (file.size > 2 * 1024 * 1024 * 1024 ) { // 文件大小最大为2g
      console.log("文件过大");
    } else {
      const chunkSize = 3 * 1024 * 1024; // 3m
      const totalChunks = Math.ceil(file.size / chunkSize);
      // debugger
      let uploadId = "";
      for (let i = 0; i < totalChunks; i++) {

        // 计算当前切片开始位置
        const start = i * chunkSize;
        // 当前切片结束位置
        const end = Math.min(start + chunkSize, file.size);
        // 切割数据
        const chunk = file.slice(start, end);
        // 转换blob
        const chunkFile = new File([chunk], `${file.name}`, {
          type: file.type,
        });
        // 设置请求参数
        const formData = new FormData();
        formData.append("file", chunkFile);
        formData.append("partNumber", String(i + 1));
        formData.append("partCount", String(totalChunks));
        formData.append("uploadId", uploadId);
        try {
          // 发起上传请求
          
          const response = await uploadShardingFile(formData);
          if (response.code === 200) {
            // 第1次之后携带后端返回uploadId
            uploadId = response.data.uploadId;
            if (response.data.ossUrl) {
              func(file, response.data.ossUrl)
            }
          }
        } catch {
          message.error('上传失败')
          console.log("上传失败=====>>>>>");
        }
      }
    }
  }

这样子,确实高效很多,视频也可以正常上传。下面大体讲述一下实现思路吧。

实现思路:

首先将文件进行切片处理,这里我们约定的是3M。 然后 按照切片后的大小,依次切片,进行传参。然后下一次的上传参数需要有上次接口返回的

uploadId。当拿到具体的视频路径后,跳出循环,说明上传完成。