前言:

前端如何将大文件上传到后台服务器,如何避免因为特殊情况导致文件上传失败而不至于重新上传。

序言

断点续传: 在下载或上传时,将下载或上传任务(一个文件或一个压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传或下载,如果碰到网络故障,可以从已经上传或下载的部分开始继续上传下载未完成的部分,而没有必要从头开始上传下载。

一、webuploader.js实现断点续传

webuploader是由百度团队开发的一个简单的以h5为主,flash为辅的现代文件上传组件,采用大文件分片并发上传,极大的提高了文件上传效率。

功能:1、分片、并发;2、预览、压缩;3、多途径添加文件;4、h5 & flash 5、md5秒传;6、易扩展、可拆分。

1、样例
该样例支持文件多选单独上传全部上传删除暂停以及进度管理

2、代码
html5代码

<head><link rel="stylesheet" type="text/css"href="https://cdnjs.cloudflare.com/ajax/libs/webuploader/0.1.1/webuploader.css"><link rel="stylesheet" type="text/css"href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"><script src="/static/js/jquery-2.0.3.min.js"></script><script src="/static/js/webuploader.js"></script><script src="/static/js/bootstrap.min.js"></script>
</head><div id="uploader" class="container"><!--用来存放文件信息--><div id="thelist" class="row"><div class="panel panel-primary"><div class="panel-heading">文件上传</div><table class="table table-striped table-bordered" id="uploadTable"><thead><tr><th>序号</th><th>文件名称</th><th>文件大小</th><th>上传状态</th><th>上传进度</th><th style="width:15%;">操作</th></tr></thead><tbody></tbody></table><div class="panel-footer"><div id="picker">选择文件</div><button id="btn" class="btn btn-default">开始上传</button></div></div></div>
</div>

script代码

<script type="text/javascript">var fileMd5;var fileSuffix;var $list = $("#thelist table>tbody");var state = 'pending';//初始按钮状态var $btn = $("#btn");var count = 0;//监听分块上传过程中的三个时间点WebUploader.Uploader.register({"before-send-file": "beforeSendFile","before-send": "beforeSend","after-send-file": "afterSendFile",}, {//时间点1:所有分块进行上传之前调用此函数beforeSendFile: function (file) {var deferred = WebUploader.Deferred();//1、计算文件的唯一标记,用于断点续传(new WebUploader.Uploader()).md5File(file, 0, 1024).progress(function (percentage) {$('#' + file.id).find("td.state").text("正在读取文件信息...");}).then(function (val) {fileMd5 = val;$('#' + file.id).find("td.state").text("成功获取文件信息...");//获取文件信息后进入下一步deferred.resolve();});return deferred.promise();},//时间点2:如果有分块上传,则每个分块上传之前调用此函数beforeSend: function (block) {var deferred = WebUploader.Deferred();$.ajax({type: "POST",url: "{% url 'checkChunk'%}",data: {//文件唯一标记fileMd5: fileMd5,//当前分块下标chunk: block.chunk,//当前分块大小chunkSize: block.end - block.start},dataType: "json",success: function (response) {if (response.ifExist) {//分块存在,跳过deferred.reject();} else {//分块不存在或不完整,重新发送该分块内容deferred.resolve();}}});this.owner.options.formData.fileMd5 = fileMd5;deferred.resolve();return deferred.promise();},//时间点3:所有分块上传成功后调用此函数afterSendFile: function (file) {//如果分块上传成功,则通知后台合并分块$.ajax({type: "POST",url: "{% url 'mergeChunks'%}",data: {fileId: file.id,fileMd5: fileMd5,fileSuffix: fileSuffix,fileName: file.name,},success: function (response) {console.log(response.fileName + " 上传成功")$('#del' + file.id).hide();}});}});var uploader = WebUploader.create({// swf文件路径swf: '/static/js/Uploader.swf',// 文件接收服务端。server: "/PV/projects/upload/",// 选择文件的按钮。可选。// 内部根据当前运行是创建,可能是input元素,也可能是flash.pick: {id: '#picker',multiple: true},// 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!resize: true,auto: false,//开启分片上传chunked: true,chunkSize: 10 * 1024 * 1024,accept: {extensions: "txt,jpg,jpeg,bmp,png,zip,rar,war,pdf,cebx,doc,docx,ppt,pptx,xls,xlsx,iso,flv,mp4",mimeTypes: '.txt,.jpg,.jpeg,.bmp,.png,.zip,.rar,.war,.pdf,.cebx,.doc,.docx,.ppt,.pptx,.xls,.xlsx,.iso,.flv,.mp4'}});// 当有文件被添加进队列的时候uploader.on('fileQueued', function (file) {//保存文件扩展名fileSuffix = file.ext;fileName = file.source['name'];var fileSize = file.size;var fileSizeStr = "";fileSizeStr = WebUploader.Base.formatSize(fileSize);count++;$list.append('<tr id="' + file.id + '" class="item" flag=0>' +'<td class="index">' + count + '</td>' +'<td class="info">' + file.name + '</td>' +'<td class="size">' + fileSizeStr + '</td>' +'<td class="state">等待上传...</td>' +'<td class="percentage"></td>' +'<td class="operate"><button name="upload" id="del' + file.id + '" class="btn btn-warning">开始</button><button name="delete" class="btn btn-error">删除</button></td></tr>');});// 文件上传过程中创建进度条实时显示。uploader.on('uploadProgress', function (file, percentage) {$('#' + file.id).find('td.percentage').text('上传中 ' + Math.round(percentage * 100) + '%');});uploader.on('uploadSuccess', function (file) {$('#' + file.id).find('td.state').text('已上传');});uploader.on('uploadError', function (file) {$('#' + file.id).find('td.state').text('上传出错');});uploader.on('uploadComplete', function (file) {uploader.removeFile(file);});uploader.on('all', function (type) {if (type === 'startUpload') {state = 'uploading';} else if (type === 'stopUpload') {state = 'paused';} else if (type === 'uploadFinished') {state = 'done';}if (state === 'uploading') {$btn.text('暂停上传');} else {$btn.text('开始上传');}});$btn.on('click', function () {if (state === 'uploading') {uploader.stop(true);} else {uploader.upload();}});$("body").on("click", "#uploadTable button[name='upload']", function () {flag = $(this).parents("tr.item").attr("flag") ^ 1;$(this).parents("tr.item").attr("flag", flag);var id = $(this).parents("tr.item").attr("id");if (flag == 1) {$(this).text("暂停");uploader.upload(uploader.getFile(id, true));} else {$(this).text("开始");uploader.stop(uploader.getFile(id, true));}});$("body").on("click", "#uploadTable button[name='delete']", function () {var id = $(this).parents("tr.item").attr("id");$(this).parents("tr.item").remove();uploader.removeFile(uploader.getFile(id, true));});
</script>
url路由代码
"跳转上传页面"
url('index/', views.index),
url('upload/', views.upload, name='upload'),
"分块上传"
url('checkChunk/', views.checkChunk, name='checkChunk'),
"上传结束合并删除分块"
url('mergeChunks/', views.mergeChunks, name='mergeChunks'),

djagno 后台代码

def upload(request):"""前端上传的分片 保存到 指定的目录下:param request: :return: """if request.method == 'POST':md5 = request.POST.get("fileMd5")chunk_id = request.POST.get("chunk", "0")fileName = "%s-%s" % (md5, chunk_id)file = request.FILES.get("file")with open(FILE_PATH + fileName, 'wb') as f:for i in file.chunks():f.write(i)return JsonResponse({'upload_part': True})def checkChunk(request):"""检查上传分片是否重复,如果重复则不提交,否则提交:param request::return:"""if request.method == 'POST':chunkSize = request.POST.get("chunkSize")if chunkSize == '0':return JsonResponse({'ifExist': True})file_name = request.POST.get('fileMd5') + request.POST.get('chunk')if file_name not in get_deep_data():return JsonResponse({'ifExist': False})return JsonResponse({'ifExist': True})def get_deep_data(path=FILE_PATH):"""判断一个文件是否在一个目录下:param path::return:"""result = []data = os.listdir(path)for i in data:if os.path.isdir(i):get_deep_data(i)else:result.append(i)return resultdef mergeChunks(request):"""将每次上传的分片合并成一个新文件,并删除分片数据:param request::return:"""if request.method == 'POST':chunk = 0id = request.POST.get("fileId")md5 = request.POST.get("fileMd5")fileName = request.POST.get("fileName")path = os.path.join(FILE_PATH, fileName)with open(path, 'wb') as fp:while True:try:filename = FILE_PATH + '/{}-{}'.format(md5, chunk)with open(filename, 'rb') as f:fp.write(f.read())os.remove(filename)except:breakchunk += 1return JsonResponse({'upload': True, 'fileName': fileName, 'fileId': id})

3、原理

1、将大文件分片;
2、每一片校验并上传分片保存到指定目录;
3、将分片数据合并成大文件,删除分片数据。

注意:js代码以及css格式可以从此处下载。

二、q.js实现断点续传

1、样例

2、代码
代码以及测试样例下载。
3、分析

Q.js可以实现多种类型的文件上传,包括文件夹上传。

【前端杂记】断点续传相关推荐

  1. 完美解决前端无法上传大文件方法

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

  2. webuploader上传文件夹

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

  3. 上传大文件(10G)的解决方案

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

  4. 图片和视频的上传(文件上传通用)

    流程如下: 1.先引入el-upload 2.调用上传前事件 3.上传前事件中将file文件转formData 4.调用后端oss接口上传文件 5.上传完成后回显数据 6.点击图片/视频预览 图片和视 ...

  5. [转] 前端实现文件的断点续传

    早就听说过断点续传这种东西,前端也可以实现一下 断点续传在前端的实现主要依赖着HTML5的新特性,所以一般来说在老旧浏览器上支持度是不高的 本文通过断点续传的简单例子(前端文件提交+后端PHP文件接收 ...

  6. js输出php文件大小,前端js实现文件的断点续传 后端PHP文件接收

    早就听说过断点续传这种东西,前端也可以实现一下. 断点续传在前端的实现主要依赖着HTML5的新特性,所以一般来说在老旧浏览器上支持度是不高的 本文通过断点续传的简单例子(前端文件提交+后端PHP文件接 ...

  7. vue前端上传文件夹的插件_基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件...

    1. 前言 之前公司要在管理系统中做一个全局上传插件,即切换各个页面的时候,上传界面还在并且上传不会受到影响,这在vue这种spa框架面前并不是什么难题.然而后端大佬说我们要实现分片上传.秒传以及断点 ...

  8. 大文件分片上传前端框架_无插件实现大文件分片上传,断点续传

    文件上传.gif 1. 简介: 本篇文章基于实际项目的开发,将介绍项目中关于大文件分片上传.文件验证.断点续传.手动重试上传等需求的使用场景及实现: 2. 项目需求 在一个音视频的添加中,既要有音视频 ...

  9. 前端js华为云obs断点续传上传

    前端js华为云obs断点续传上传 断点续传上传就是将待上传的文件分成若干份分别上传,并实时地将每段上传结果统一记录在断点续传记录对象中,仅当所有分段都上传成功时返回上传成功的结果,否则在回调函数中返回 ...

  10. 前端大文件上传断点续传解决方案

    之前仿造uploadify写了一个HTML5版的文件上传插件,没看过的朋友可以点此先看一下~得到了不少朋友的好评,我自己也用在了项目中,不论是用户头像上传,还是各种媒体文件的上传,以及各种个性的业务需 ...

最新文章

  1. linux学习笔记十四:安装SAMBA(Server Message Block)
  2. centos7升级自带的php5.4版本到php5.6
  3. ubuntu下超级用户和普通用户
  4. 你对5G技术“低延时”可能有些误解——专访虎牙5G 首席架构师林正显
  5. 第十三期:你所了解的javascript?
  6. treeview 文字垂直方向_word文本排版技巧:改变文字方向的这些方法,你知道吗?...
  7. java高级必须懂得_反射---Java高级开发必须懂的
  8. CPython 标准库源码分析 collections.Counter
  9. 关于scanf 函数,你很少了解的“秘密”
  10. 查看和设置tomcat内存
  11. zabbix3.2监测mysql_zabbix3.2监控MYSQL状态
  12. golang 猜数字小游戏
  13. 软件设计师教程-倪奕文-专题视频课程
  14. 88.合并两个有序数组
  15. 聪明的笨鸟(人-AI试验版)
  16. Lotus配置之六:IBM Lotus Note添加公共邮箱
  17. bp神经网络缺点及克服,bp神经网络存在的问题
  18. LC117 Populating Next Right Pointers in Each Node II
  19. day46第九章动态规划(二刷)
  20. Unity3D 大型游戏 最后一站 源码 部分重点匹配战斗(四)(13)

热门文章

  1. 卸载HP LaserJet 激光打印机的驱动程序--Win7环境
  2. [ScyllaHide] 05 ScyllaHide的Hook原理
  3. JMeter下载安装以及使用教程
  4. 10本Java架构师必读书籍推荐
  5. 自定义http报头_Http请求报头设置
  6. android交叉编译libxml2,libxml2 ARM 交叉编译
  7. php tp框架,TP框架
  8. springboot框架(2):整合junit4
  9. 精品思维导图模板合集,锻炼你的逻辑思维,提升能力空间
  10. proj编译linux,安装OpenProj配置中文显示