根据部门的业务需求,需要在网络状态不良的情况下上传很大的文件(1G+)。
其中会遇到的问题:
1,文件过大,超出服务端的请求大小限制;
2,请求时间过长,请求超时;
3,传输中断,必须重新上传导致前功尽弃。
解决方案实现思路,拿到文件,保存文件唯一性标识,切割文件、分片上传、文件MD5验证、断点续传、手动重试上传。

鉴于过往有使用过webupload文件上传组件的经验,于是此次采用的是Plupload作为替换。Plupload是一款由著名的web编辑器TinyMCE团队开发的上传组件,简单易用且功能强大。

Plupload有以下功能和特点

  1. 拥有多种上传方式:HTML5、flash、silverlight以及传统的<input type=”file” />。Plupload会自动侦测当前的环境,选择最合适的上传方式,并且会优先使用HTML5的方式。所以你完全不用去操心当前的浏览器支持哪些上传方式,Plupload会自动为你选择最合适的方式。
  2. 支持以拖拽的方式来选取要上传的文件
  3. 支持在前端压缩图片,即在图片文件还未上传之前就对它进行压缩
  4. 可以直接读取原生的文件数据,这样的好处就是例如可以在图片文件还未上传之前就能把它显示在页面上预览
  5. 支持把大文件切割成小片进行上传,因为有些浏览器对很大的文件比如几G的一些文件无法上传。

环境

  • vue2.x
  • webpack3.x
  • axios

代码

npm安装plupload,文件引入组件,

1
2
3
4
5
6
7
8
9
10
11
12
<uploader browse_button="upload_area"
                :max_retries="3"
                :url="action"
                :headers="headers"
                chunk_size="10MB"
                drop_element="upload_area"
                @disableBrowse="!loading"
                :BeforeUpload="beforeUpload"
                :ChunkUploaded="chunkUploaded"
                :FilesAdded="filesAdded"
                :StateChanged="stateChanged"
                @inputUploader="inputUploader" />

  

初始化方法filesAdded(),每次上传前清空队列的其他文件,保证上传的一致性。其次对文件类型进行判断过滤fileType(),文件进入时进行总md5一次fileMd5(),然后进入文件分片chunkCheckStatus(),每个分片都要进行md5并与后台进行校验fileMd5(),确保文件在中断后继续上传的准确性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
filesAdded (up, files) {
      // 删除上传队列中其他文件,只保留最近上传的文件
      let fileLen = files.length, that = this
      if (fileLen > 1) {
        files = files.splice(0, fileLen - 1)// 清空上传队列
      }
      files.forEach((f) => {
        f.status = -1
        that.dataForm.file = f
        that.fileType(f.getNative())
        if (that.loading) {
          that.computeStatus = true
          that.progress = 0
          // 文件分片
          let chunkSize = 2097152, // Read in chunks of 2MB
            chunks = Math.ceil(f.size / chunkSize)
          that.fileMd5(f.getNative(), (e, md5) => {
            that.dataForm.md5 = md5
            if (that.loading == true) {
              that.count = 0
              that.chunkCheckStatus(md5, that.dataForm.fileName, (uploader, dataList) => {
                that.uploading = uploader
                if (that.uploading == true) {
                  for (let chunk = 1; chunk <= chunks; chunk++) {
                    that.fileChunkFile(f.getNative(), chunk, (e, chunkFile) => {
                      that.fileMd5(chunkFile, (e, blockMd5) => {
                        that.PostFile(up, chunkFile, chunk, chunks, md5, blockMd5)
                      })
                    })
                  }
                else {
                  // 去重
                  that.progress = 0
                  for (let chunk = 1; chunk <= chunks; chunk++) {
                    let status = 0
                    dataList.some((item) => {
                      if (item.chunk == chunk) {
                        status = 1
                        return false
                      }
                    })
                    if (status == 0) {
                      that.fileChunkFile(f.getNative(), chunk, (e, chunkFile) => {
                        that.fileMd5(chunkFile, (e, blockMd5) => {
                          that.PostFile(up, chunkFile, chunk, chunks, md5, blockMd5)
                        })
                      })
                    }
                  }
                }
              })
            }
          })
        }
      })
    }

  

文件md5方法,这里使用了SparkMD5,import SparkMD5 from 'spark-md5'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
fileMd5 (file, callback) {
      let that = this
      var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
        file = file,
        chunkSize = 2097152, // Read in chunks of 2MB
        chunks = Math.ceil(file.size / chunkSize),
        currentChunk = 0,
        spark = new SparkMD5.ArrayBuffer(),
        fileReader = new FileReader()
      fileReader.onload = function (e) {
        console.log('read chunk nr', currentChunk + 1, 'of', chunks)
        spark.append(e.target.result) // Append array buffer
        currentChunk++
        if (currentChunk < chunks) {
          loadNext()
        else {
          let blockMd5 = ''
          blockMd5 = spark.end()
          callback(null, blockMd5)
        }
      }
      fileReader.onerror = function () {
        callback('oops, something went wrong.')
      }
      function loadNext () {
        var start = currentChunk * chunkSize,
          end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize
        fileReader.readAsArrayBuffer(blobSlice.call(file, start, end))
      }
      loadNext()
    }

  

文件分片上传方法,验证总分片信息后,把每个分片进行md5加密并上传校验,这里有写进度条相关的控制,不一一展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
chunkCheckStatus (md5, fileName, callback) {
      this.$http({
        url: this.$http.adornUrl('/biz/upload/getFileBlockStatus'),
        method: 'get',
        params: this.$http.adornParams({
          md5: md5,
          fileName: fileName
        })
      }).then(({ data }) => {
        if (data && data.code === 0) {
          if (data.list != null) {
            this.uploading = false
            this.chunkCheckData = []
            data.list.map((item, index) => {
              if (item.isUpload == true) {
                this.count++
                this.chunkCheckData.push(item)
              }
            })
            callback(this.uploading, this.chunkCheckData)
            return
          }
          this.uploading = true
          callback(this.uploading)
        else {
          this.$message.error(data.msg)
          this.loading = false
          this.computeStatus = false
          return false
        }
      })
    }

  

详细的配置信息可以参考我写的这篇文章:http://blog.ncmem.com/wordpress/2019/08/09/vue%e5%a4%a7%e6%96%87%e4%bb%b6%e6%96%ad%e7%82%b9%e7%bb%ad%e4%bc%a0/

vue+大文件断点续传的更多相关文章

  1. iOS开发之网络编程--使用NSURLConnection实现大文件断点续传下载+使用输出流代替文件句柄

    前言:本篇讲解,在前篇iOS开发之网络编程--使用NSURLConnection实现大文件断点续传下载的基础上,使用输出流代替文件句柄实现大文件断点续传.    在实际开发中,输入输出流用的比较少,但 ...

  2. php实现大文件断点续传下载实例

    php实现大文件断点续传下载实例,看完你就知道超过100M以上的大文件如何断点传输了,这个功能还是比较经典实用的,毕竟大文件上传功能经常用得到. require_once('download.clas ...

  3. vue大文件上传控件选哪个好?

    需求: 项目要支持大文件上传功能,经过讨论,初步将文件上传大小控制在20G内,因此自己需要在项目中进行文件上传部分的调整和配置,自己将大小都以20G来进行限制. PC端全平台支持,要求支持Window ...

  4. HTML5 大文件断点续传完整思路整理

    需求: 支持大文件批量上传(20G)和下载,同时需要保证上传期间用户电脑不出现卡死等体验: 内网百兆网络上传速度为12MB/S 服务器内存占用低 支持文件夹上传,文件夹中的文件数量达到1万个以上,且包 ...

  5. B/S大文件断点续传

    一. 功能性需求与非功能性需求 要求操作便利,一次选择多个文件和文件夹进行上传:支持PC端全平台操作系统,Windows,Linux,Mac 支持文件和文件夹的批量下载,断点续传.刷新页面后继续传输. ...

  6. vue+大文件分片上传

    最近公司在使用vue做工程项目,实现大文件分片上传. 网上找了一天,发现网上很多代码都存在很多问题,最后终于找到了一个符合要求的项目. 工程如下: 对项目的大文件上传功能做出分析,怎么实现大文件分片上 ...

  7. webUploader大文件断点续传学习心得 多文件

    二.Jsp代码: <!-- 断点续传   start--> <!-- 隐藏域 实时保存上传进度 --> <input id="jindutiao" t ...

  8. js解决大文件断点续传

    最近遇见一个需要上传百兆大文件的需求,调研了七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现. 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表 ...

  9. .net解决大文件断点续传

    以ASP.NET Core WebAPI 作后端 API ,用 Vue 构建前端页面,用 Axios 从前端访问后端 API ,包括文件的上传和下载. 准备文件上传的API #region 文件上传  ...

随机推荐

  1. 1.Hbase简介

    1. Hbase简介 1.1. 什么是hbase(面向列) HBASE是一个高可靠性.高性能.面向列.可伸缩的分布式存储系统,利用HBASE技术可在廉价PC Server上搭建起大规模 结构化存储集群 ...

  2. 搭建nginx文件服务器

    一.安装nginx服务 apt install nginx 二.修改nginx配置文件 cd /etc/nginx/conf.d/ vim download_server.conf server { ...

  3. 一个异常研究InvalidApartmentStateChange

    微软资料:invalidApartmentStateChange MDA 地址:https://docs.microsoft.com/zh-cn/dotnet/framework/debug-trac ...

  4. mongodb索引 复合索引

    当我们的查询条件不只有一个时,就需要建立复合索引,比如插入一条{x:1,y:2,z:3}记录,按照我们之前建立的x为1的索引,可是使用x查询,现在想按照x与y的值查询,就需要创建如下的索引     创 ...

  5. Codeforces Round #590 (Div. 3) 万恶的自己WAC

    C题:一道简单的C题卡了半天,我太菜了 题意:给你一个n*2的矩阵,每个位置有一个数字,对应一种管道,要求通道可不可以从左上通到右下 由提议可以看出,1,2对应的是直管道,3,4,5,6对应弯管道,只 ...

  6. python 学习笔记_1 pip安装、卸载、更新包相关操作及数据类型学习

    '''prepare_1 pip安装.卸载.更新组件type 各数据类型''' py -3 -m pip py -3 -m pip listpy -3 -m pip show nosepy -3 -m ...

  7. php高精度计算

  8. JavaScript002,验证输入

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  9. watch 监控的新旧值一致问题处理

    watch 监控的新旧值一致问题处理 http://www.imooc.com/article/details/id/286654

  10. python 获取指定字符前面或后面的所有字符

    要求:获取某个字符指定字符的前面或后面的所有字符内容 示例: URL = https://www.baid/v2/user/login (1)想要获取v2的数据:v2/user/login print ...