WebUploader实现大文件上传

1,445 阅读1分钟

theme: mk-cute highlight: atelier-lakeside-light

WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件。采用大文件分片并发上传,极大的提高了文件上传效率。

Web Uploader下载命令:npm install webuploader 依赖: jquery下载老版本:^1.12.0

1.创建dom结构

<div class="uploader">
    <co-button type="info" id="picker"></co-button>
    <co-button id="ctlBtn" type="success">上传到服务器</co-button>
</div>

2.初始化WebUploader

设置上传文件的一些基础配置

let uploader = WebUploader.create({
    pick: {
        id: '#picker', // 指定选择文件的按钮
        innerHTML: '选择文件' // 设置按钮文案
    },
    accept: {
       extensions: 'zip', // 可接受上传的文件类型
       mimeTypes: '.zip', // mime类型 
    },
    // 上传所需请求参数
    formData: {
        chunkSize: 50 * 1024 * 1024, // 分片大小(50MB)lp
    },
    swf: 'http://cdn.staticfile.org/webuploader/0.1.0/Uploader.swf', // swf文件路径
    server: `${window.markEnv.backend_url}/api/mark/file/upload`, // 请求路径
    disableGlobalDnd: true, // 是否禁掉整个页面的拖拽功能
    auto: false, // 是否有文件选择即开始上传
    chunked: true, // 是否要分片处理大文件上传
    threads: 6, // 并发量
    timeout: 0, // 超时时间
})

3.在uploader实例化之前注入Hook

  1. 生成MD5之后开始切片并上传到服务端
  2. 这里需要服务端配合返回对应的状态码,判断本次上传的文件状态
WebUploader.Uploader.register(
    {
        name: 'contractUpload',
        'before-send-file': 'beforeSendFile', // 在文件发送之前request,此时还没有分片
        'before-send': 'beforeSend', // 在分片发送之前request,可以用来做分片验证
    },
    {
        beforeSendFile: function (file) {
          // Deferred对象在钩子回掉函数中经常要用到,用来处理需要等待的异步操作。
          let task = new $.Deferred()
          // 根据文件内容来查询MD5
          uploader
            .md5File(file)
            .progress(function (percentage) {
              // 显示进度
              if (that.tableData[0])
                this.tableData[0].md5Loading = Number(
                  (percentage * 100).toFixed(1)
                )
            })
            .then(function (val) {
              // 完成
              file.md5 = val
              // 开始上传切边
              Ajax.post('/api/mark/file/check', {
                md5: file.md5,
                dataType,
              })
                .then((data) => {
                  let status = data.code
                  task.resolve()
                  switch (status) {
                    case 200:
                      // 正常流程
                      that.$message.success(data.msg)
                      break
                    case 100:
                      // 忽略上传过程,直接标识上传成功;
                      that.$message.warning(data.msg)
                      that.tableData[0].state = data.msg.split('!')[0]
                      uploader.reset()
                      uploader.skipFile(file)
                      file.pass = true
                      break
                    case 102:
                      // 部分已经上传到服务器了,但是差几个模块。
                      that.$message.warning(data.msg)
                      file.missChunks = data.data
                      break
                    case 103:
                      // 表示正在解压
                      that.$message.warning(data.msg)
                      that.tableData[0].state = data.msg.split('!')[0]
                      uploader.reset()
                      uploader.skipFile(file)
                      file.pass = true
                      break
                    case 500:
                      that.$message.error(data.msg)
                      uploader.reset()
                      break
                    default:
                      break
                  }
                })
                .catch((err) => {
                  that.$message.error(err.msg + '')
                  that.isLoading = false
                  uploader.reset()
                })
            })
          return $.when(task)
        },
)

4.监听上传状态

// 当有文件被添加进队列的时候
uploader.on("fileQueued", function (file) {
    this.tableData.unshift({
        name: file.name.split(".")[0],
        size: (file.size / 1024 / 1024).toFixed(2) + "(MB)",
        type: file.ext,
        time: "———",
        state: "等待上传中",
        md5Loading: 0,
        allLoading: 0,
    });
});
// 当某个文件的分块在发送前触发,主要用来询问是否要添加附带参数
// 大文件在开起分片上传的前提下此事件可能会触发多次
uploader.onUploadBeforeSend = function (obj, data) {
    let file = obj.file;
    data.md5 = file.md5 || "";
    data.uid = file.uid;
};
// 上传中
uploader.on("uploadProgress", function (file, percentage) {
    let time = new Date();
    this.tableData[0].state = "上传中";
    this.tableData[0].time = time.toLocaleString();
    this.tableData[0].allLoading = Number((percentage * 100).toFixed(1));
});
// 上传成功返回结果
uploader.on("uploadSuccess", function (file) {
    this.tableData[0].state = "上传完成";
    this.isLoading = false;
    uploader.reset();
});
// 上传失败返回结果
uploader.on("uploadError", function (file) {
    this.isLoading = false;
    this.tableData[0].state = "上传失败";
    this.$message.error("上传失败,请稍后重试!");
    uploader.reset();
});

5.组件销毁之前清除注册事件

如果不对当前组件进行处理,当其它组件再次使用时,beforeSendFile会调用上一次缓存的记录

WebUploader.Uploader.unRegister("contractUpload");