美文网首页
文件分片上传

文件分片上传

作者: Neuro_annie | 来源:发表于2024-08-07 16:12 被阅读0次
    import md5 from "@/utils/uploadMD5";  //见上一篇文章封装MD5
    import { taskInfoService, initTaskService, mergeUploadService } from "@/api/chunkUploadFile";
    const FILE_CHUNKSIZE = 5 * 1024 * 1024;
    const BlobSlice =
      File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
    let failCount = 0;
    
    //定义data
    data() {
      return {
        file: null,
        fileMd5: "",
        uploadId: "",
        fileName: "",
        simultaneousUploads: 3,  //并发数
        uploadPercentage: 0,  //上传进度
        uploadFail: false,  //上传失败
      };
    }
    
    async fileUpload() {
      this.file.chunkList = [];
      this.fileMd5 = await md5(this.file, FILE_CHUNKSIZE);
    
      const checkRes = await taskInfoService(this.fileMd5); //检查是否已上传
      if (checkRes.code === 100000) {
        // 已上传
        this.uploadPercentage = 100;
        return;
      }
      if (checkRes.code === 300000) {
        // 上传失败
        this.uploadFail = false;
        return;
      }
      let fileChunks = this.createFileChunk();
      const initTaskData = {
        fileMd5: this.fileMd5,
        fileName: this.file.name,
        fileSize: this.file.size,
        chunkSize: FILE_CHUNKSIZE,
        partCount: Math.ceil(this.file.size / FILE_CHUNKSIZE),
        rtspUrl: this.fileInfo.rtspUrl,
        beginTime: this.fileInfo.beginTime,
        endTime: this.fileInfo.endTime,
        fileType: this.fileInfo.type,
      };
      if (checkRes.code === 2000000) {
        // 断点续传
        const uploadedList = checkRes.urlList;  //已上传成功的切片列表
        uploadedList.forEach((uploaded) => {
          let index = this.fileChunks.findIndex((item) => item === uploaded);
          if (index !== -1) {
            this.fileChunks.splice(index, 1);
          }
        });
      }
      // 文件未上传
      const initRes = await initTaskService(initTaskData);  //获取各切片上传地址
      let uploadUrls = initRes.data.urlList;
      this.uploadId = initRes.data.uploadId;
      this.fileName = initRes.data.fileName;
      fileChunks.map((chunkItem, index) => {
        this.file.chunkList.push({
          chunkNumber: index + 1,
          chunk: chunkItem,
          uploadUrl: uploadUrls[index],
        });
      });
      // 上传
      await this.uploadChunkBase(this.file.chunkList);
      // 合并文件
      await mergeUploadService({
        uploadId: this.uploadId,
        fileName: this.fileName,
        fileMd5: this.fileMd5,
        rtspUrl: this.fileInfo.rtspUrl,
        beginTime: this.fileInfo.beginTime,
        endTime: this.fileInfo.endTime,
        fileType: this.fileInfo.type,
      });
    }
    
    //各切片上传
    uploadChunkBase(chunkList) {
      let successCount = 0;
      let totalChunks = chunkList.length;
      return new Promise((resolve, reject) => {
        const handler = () => {
          if (chunkList.length) {
            const chunkItem = chunkList.shift();
            // 直接上传二进制,不需要构造 FormData,否则上传后文件损坏
            axios
              .put(chunkItem.uploadUrl, chunkItem.chunk.file, {
                // 上传进度处理
                headers: {
                  "Content-Type": "application/octet-stream",
                },
              })
              .then((response) => {
                if (response.status === 200) {
                  console.log("分片:" + chunkItem.chunkNumber + " 上传成功");
                  successCount++;
                  this.uploadPercentage = (successCount / totalChunks) * 100;
                  // 继续上传下一个分片
                  handler();
                } else {
                  console.log(
                    "上传失败:" + response.status + "," + response.statusText
                  );
                }
              })
              .catch((error) => {
                // 失败后只上传五次,防止卡死
                failCount++;
                if (failCount < 5) {
                  // 更新状态
                  console.log(
                    "分片:" + chunkItem.chunkNumber + " 上传失败," + error
                  );
                  // 重新添加到队列中
                  chunkList.push(chunkItem);
                  handler();
                } else {
                  this.$message.error(
                    "分片:" + chunkItem.chunkNumber + " 上传失败"
                  );
                }
              });
          }
          if (successCount >= totalChunks) {
            resolve();
          }
        };
        // 并发  import Queue from 'promise-queue-plus';
        for (let i = 0; i < this.simultaneousUploads; i++) {
          handler();
        }
      });
    }
    
    // 文件分片
    createFileChunk() {
      const fileChunkList = [];
      let count = 0;
      while (count < this.file.size) {
        fileChunkList.push({
          file: BlobSlice.call(this.file, count, count + FILE_CHUNKSIZE),
        });
        count += FILE_CHUNKSIZE;
      }
      return fileChunkList;
    }
    

    相关文章

      网友评论

          本文标题:文件分片上传

          本文链接:https://www.haomeiwen.com/subject/pdofkjtx.html