背景

根据部门的业务需求,需要在网络状态不良的情况下上传很大的文件(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,文件引入组件,

<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(),确保文件在中断后继续上传的准确性。

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'

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加密并上传校验,这里有写进度条相关的控制,不一一展示

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
}
})
}

  

总结


上图可以清晰的说明文件加密上传的传输流程,在文件上传加密及Content-Type格式需要与后台协商一致,通常有base64、multipart/form-data两种类型,要清晰了解分片算法及md5,自定义上传文件异步代码,除此之外,可拖拽上传文件、进度条控制等可更好的丰富文件上传体验。

注意

功能在某些旧版浏览器中不起作用。

参考

https://www.plupload.com/

Vue.js实现大文件分片md5断点续传的更多相关文章

  1. Node + js实现大文件分片上传基本原理及实践(一)

    _ 阅读目录 一:什么是分片上传? 二:理解Blob对象中的slice方法对文件进行分割及其他知识点 三. 使用 spark-md5 生成 md5文件 四. 使用koa+js实现大文件分片上传实践 回 ...

  2. js实现大文件分片上传的方法

    借助js的Blob对象FormData对象可以实现大文件分片上传的功能,关于Blob和FormData的具体使用方法可以到如下地址去查看FormData 对象的使用Blob 对象的使用以下是实现代码, ...

  3. webUploader实现大文件分片,断点续传

    问题: 公司现在的业务需求是要上传一个大文件,上一次写了一篇博客,做了一个简单的文件上传,支持单文件,大型文件上传 现在对之前的上传进行优化,支持断点续传,秒传功能 上次博客:[http://www. ...

  4. js+php大文件分片上传

    1 背景 用户本地有一份txt或者csv文件,无论是从业务数据库导出.还是其他途径获取,当需要使用蚂蚁的大数据分析工具进行数据加工.挖掘和共创应用的时候,首先要将本地文件上传至ODPS,普通的小文件通 ...

  5. php+html5实现无刷新上传,大文件分片上传,断点续传

    核心原理: 该项目核心就是文件分块上传.前后端要高度配合,需要双方约定好一些数据,才能完成大文件分块,我们在项目中要重点解决的以下问题. * 如何分片: * 如何合成一个文件: * 中断了从哪个分片开 ...

  6. nodeJs + js 大文件分片上传

    简单的文件上传 一.准备文件上传的条件: 1.安装nodejs环境 2.安装vue环境 3.验证环境是否安装成功 二.实现上传步骤 1.前端部分使用 vue-cli 脚手架,搭建一个 demo 版本, ...

  7. vue+大文件分片上传

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

  8. iOS大文件分片上传和断点续传

    总结一下大文件分片上传和断点续传的问题.因为文件过大(比如1G以上),必须要考虑上传过程网络中断的情况.http的网络请求中本身就已经具备了分片上传功能,当传输的文件比较大时,http协议自动会将文件 ...

  9. PHP大文件分片上传

    前段时间做视频上传业务,通过网页上传视频到服务器. 视频大小 小则几十M,大则 1G+,以一般的HTTP请求发送数据的方式的话,会遇到的问题:1,文件过大,超出服务端的请求大小限制:2,请求时间过长, ...

随机推荐

  1. 两个对象值相同(x.equals(y)==true),但却可有不同的hashcode这句话对吗?

    1.这句话当然不对啦,请参看官方文档给出的解释! hashCode public int hashCode()返回该对象的哈希码值.支持此方法是为了提高哈希表(例如 java.util.Hashtab ...

  2. python画樱花

    用python画简单的樱花 代码如下: import turtle as T import random import time # 画樱花的躯干(60,t) def Tree(branch, t): ...

  3. 第二章 Unity Shader基础

    [TOC] 1. Unity Shader 的基础: ShaderLab 学习和编写着色器的过程一直是一个学习曲线很陡峭的过程,通常情况下为了自定义渲染效果往往要和很多文件和设置打交道,这些设置很容易 ...

  4. 链式栈-C语言实现

    相对于顺序栈的空间有限,链式栈的操作则更加灵活 #include<stdio.h> #include<malloc.h> typedef int SElemType; //元素 ...

  5. WPF最简单的分页控件

    背景:最近在写项目的时候需要写一个简单的分页功能,因项目需要,没有改为MVVM模式,只需要在后台实现 1.呈现效果如下: 接下来就来上代码,看看怎么实现的 1.界面代码 <StackPanel ...

  6. AI:为你写诗,为你做不可能的事

    最近,一档全程高能的神仙节目,高调地杀入了我们的视野: 没错,就是撒贝宁主持,董卿.康辉等央视名嘴作为评审嘉宾,同时集齐央视"三大名嘴"同台的央视<主持人大赛>,这够不 ...

  7. 补习系列(20)-大话 WebSocket 与 "尬聊"的实现

    目录 一.聊聊 WebSocket 二.Stomp 是个什么鬼 三.SpringBoot 整合 WebSocket A. 引入依赖 B. WebSocket 配置 C. 控制器 D. 前端实现 四.参 ...

  8. 求局域网内所有在线主机的ip

    在一个局域网内,已知其中一台主机的ip为192.,子网掩码为255.,求所有其他在线主机的ip. shell 编码实现 #!/bin/bash netWorkIP=. ) do $netWorkIP$ ...

  9. 用Selenium自动化测试时,让ChromeDriver中不显示“正受到自动测试软件控制”

    背景: 在用Selenium做自动化测试的时候,默认ChromeDriver是会提示“Chrom正受到自动测试软件控制”的.如下图这样.但我们有些场景下,不希望这个提示出现.本文探索了几种语言去掉这个 ...

  10. ThinkPHP的视图和模板

    简单来说一个控制器对应一个视图,一个方法对应一个模板下面我们直接上图. 二.给模板赋值 给模板赋值在这里用到了assign()这个函数,assign()函数第一个参数为给这个值自定义名称,第二个参数则 ...