背景

根据部门的业务需求,需要在网络状态不良的情况下上传很大的文件(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. 经典算法之K近邻(回归部分)

    1.算法原理 1.分类和回归 分类模型和回归模型本质一样,分类模型是将回归模型的输出离散化. 一般来说,回归问题通常是用来预测一个值,如预测房价.未来的天气情况等等,例如一个产品的实际价格为500元, ...

  2. Linux上ES单机版安装

    设置 IP 地址 vi /etc/sysconfig/network-scripts/ifcfg-ens32   重启网卡 [root@localhost ~] systemctl restart n ...

  3. Kotlin Coroutines在Android中的实践

    Coroutines在Android中的实践 前面两篇文章讲了协程的基础知识和协程的通信. 见: Kotlin Coroutines不复杂, 我来帮你理一理 Kotlin协程通信机制: Channel ...

  4. 格式化JS代码

    平常在项目中经常会遇到下载别人的js文件都是加密过的,不方便阅读都是一整行, 个人无法进行阅读,浏览器能够识别出来,所以就可以使用浏览器进行格式化js代码: 1.打开浏览器chrome为例,打开使用j ...

  5. Day01-变量/常量/数据类型/流程控制之 if

    1.变量 把程序运行的中间结果临时的存在内存里,以便后续的代码调用.代指一些复杂的.过长的数据. 声明变量  name = 'Dylan' # 把数据'Dylan'声明(赋值)给变量 nmae,以便后 ...

  6. MATLAB工具包——curvelet变换的理解(转)

    curvelet下载的curvelet工具包,有以下三个文件:fdct_usfft_matlab.fdct_wrapping_matlab.mecv三个文件夹添加到matlab路径中即可. curve ...

  7. 开发者如何学好 MongoDB

    作为一名研发,数据库是或多或少都会接触到的技术. MongoDB 是当前火热的 NoSQL 之一,我们怎样才能学好 MongoDB 呢?本篇文章,我们将从以下几方面讨论这个话题: MongoDB 是什 ...

  8. hibernate查询方式(四)

    ---恢复内容开始--- 1.mysql中的多表联合查询 ****/*内连接查询*/  只显示两个表有关联的记录 //第一种 SELECT * FROM Class c ,Student s WHER ...

  9. keychain 的学习

    keychain 的使用    http://www.cnblogs.com/ios8/archive/2012/06/25/iOS-keychain.html

  10. cf round 598div3 D.Binary String Minimizing

    题目:https://codeforces.com/contest/1256/problem/D 题意:给你长度为n的01串,能将任意两相邻字符交换k次,求最小字典序的交换结果. 思路:贪心...甚至 ...