Vue大文件切片上传 断点续传
一、中等文件上传解决方案-nginx放行
在我们工作中,上传功能最常见的就是excel的上传功能,一般来说,一个excel的大小在10MB以内吧,如果有好几十MB的excel,就勉强算是中等文件吧,此时,我们需要设置nginx的client_max_body_size值,将其放开,只不过一次上传一个几十MB的文件,接口会慢一些,不过也勉强能够接受
二、大文件上传解决方案 -- 文件切片上传 断点续传
思路:
1、把大文件切成每块10M(按照你自己的要求),然后依次上传(为了让你好理解,你可以理解成分页,一共89条数据,每页数10条,一共9页)
2、上传完成后端把文件封装好,返回上传的url地址 加上进度条
3、中途上传中断,如果再次上传如何回到原来的位置继续上传,解决办法就是每次上传前给后端请求接口查验下,该文件上传到第几片了,和后端对接好chunk参数,比如-1代表已经上传完,0代表第0片,以此类推。
完善各种情况:比如发生错误,是否可以尝试重新上传,离开页面以后取消上传操作(离开页面以后,上传还在继续,这种情况除了上传还有计时器的问题,这里就不多说了,总之离开之前先清掉的思路)
PS:一定要上传完一个才能上传完下一个,是串行不是并行,另外,ajax一定要是异步的不管是原生还是jq的ajax,因为我开始弄成同步,progress事件根本出不来
后台需要提供三个接口
1、上传文件的接口
2、上传之前查验文件是否上传过,上传到第几片的接口
3、上传文件完成merge的接口
具体逻辑 Vue
<template>
<div>
<input id="file" name="file" type="file"/>
<el-button size="small" type="primary" id="startBtn">上传视频</el-button>
<el-progress style="width: 400px" v-if="percentage==100 && !isError" :percentage="percentage" status="success"></el-progress>
<el-progress style="width: 400px" :percentage="percentage" v-else-if="percentage > 0 && !isError && percentage < 100"></el-progress>
<el-progress style="width: 400px" :percentage="percentage" status="exception" v-else-if="isError"></el-progress>
</div>
</template>
<script>
export default {
data() {
return {
percentage: 0, // 进度条
isError: false, // 是否发生错误
request: null // ajax请求
}
},
mounted() {
var pecent;
var start;
var end;
var file;
var name;
var size;
var shardCount;
var i = 0;
var shardSize;
var GUID;
var status = 0;
var _this = this;
var page = {
init: function(){
$("#startBtn").click($.proxy(this.upload, this));
},
upload: function(){
status = 0;
file = $("#file")[0].files[0]; //文件对象
if (!file) {
_this.$message.warning('请选择文件');
return;
}
name = file.name; //文件名
size = file.size; //总大小
GUID = this.guid(file.name, file.lastModified, file.size, file.type);
shardSize = 10 * 1024 * 1024; //以1MB为一个分片
shardCount = Math.ceil(size / shardSize); //总片数
// 获取当前的片数
let formData = new FormData();
formData.append("md5", GUID);
getCurrentFileChunk(formData).then(res => {
if (res.result.chunk < 0) {
_this.form.videoUrl = res.result.url;
_this.percentage = 100;
} else {
status = res.result.chunk;
start = res.result.chunk * shardSize;
end = Math.min(size, start + shardSize);
var partFile = file.slice(start,end);
var pecent=100*(start * shardSize)/file.size;
_this.percentage = parseInt(pecent);
this.partUpload(GUID,partFile,name,shardCount,status);
}
});
},
partUpload:function(GUID,partFile,name,chunks,chunk){
// 重新上传的时候
_this.isError = false;
//构造一个表单,FormData是HTML5新增的
var now = this;
var form = new FormData();
form.append("md5", GUID);
form.append("file", partFile); //slice方法用于切出文件的一部分
form.append("chunk", chunk); //当前是第几片
//form.append("chunks", chunks); //总片数
//Ajax提交
_this.request = $.ajax({
url: process.env.API_F_URL + "/files/uploadVideo",
type: "POST",
data: form,
async: true, //同步
processData: false, //很重要,告诉jquery不要对form进行处理
contentType: false, //很重要,指定为false才能形成正确的Content-Type
success: function(data){
status++;
if (status < chunks) {
start = status * shardSize,
end = Math.min(size, start + shardSize);
var partFile = file.slice(start,end);
now.partUpload(GUID,partFile,name,shardCount,status);
}
// if(data.code == 200){
// $("#output").html(status+ " / " + chunks);
// }
if(status==chunks){
now.mergeFile(GUID,name, chunks);
}
},
error: function(err) {
console.log('err', err);
if (err.statusText === 'abort') {
_this.$message.warning('已取消上传');
} else {
_this.isError = true;
_this.$message.error('上传失败,请重新上传');
// 上传失败,再次上传
// start = status * shardSize,
// end = Math.min(size, start + shardSize);
// var partFile = file.slice(start,end);
// now.partUpload(GUID,partFile,name,shardCount,status);
}
},
xhr: function () {
//获取ajax中的ajaxSettings的xhr对象 为他的upload属性绑定progress事件的处理函数
var myXhr = $.ajaxSettings.xhr();
if (myXhr.upload) {
//检查其属性upload是否存在
myXhr.upload.addEventListener("progress", function(ev){
if(ev.lengthComputable){
pecent=100*(ev.loaded+start)/file.size;
if(pecent>99){
pecent=99;
}
_this.percentage = parseInt(pecent);
}
}, false);
}
return myXhr;
},
});
},
mergeFile:function(GUID,name,chunks){
var formMerge = new FormData();
formMerge.append("md5", GUID);
formMerge.append("fileName", name);
formMerge.append("chunks", chunks);
$.ajax({
url: process.env.API_F_URL + "/files/mergeVideo",
type: "POST",
data: formMerge,
processData: false, //很重要,告诉jquery不要对form进行处理
contentType: false, //很重要,指定为false才能形成正确的Content-Type
success: function(res){
if (res.status == 'success') {
_this.isError = false;
_this.form.videoUrl = res.result.url;
_this.percentage = 100;
} else {
_this.isError = true;
_this.$message.error('上传失败,请重新上传');
}
},
error: function(err) {
_this.isError = true;
_this.$message.error('上传失败,请重新上传');
}
});
},
guid:function(name, lastModified, size, type){
return md5(name+'#'+lastModified+'#'+size+'#'+type);
}
};
$(function(){
page.init();
});
},
beforeDestroy() {
this.request.abort();
}
}
</script>
参考文章:http://blog.ncmem.com/wordpress/2023/10/31/vue%e5%a4%a7%e6%96%87%e4%bb%b6%e5%88%87%e7%89%87%e4%b8%8a%e4%bc%a0-%e6%96%ad%e7%82%b9%e7%bb%ad%e4%bc%a0/
欢迎入群一起讨论
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
2019-10-31 网页端如何实现大文件上传并支持断点续传?
2019-10-31 解决html5大文件断点续传
2019-10-31 网页内实现大文件分片上传、断点续传
2019-10-31 大文件的分片传,断点续传,md5校验
2019-10-31 c# B/S下 如何优化文件上传速度和实现断点续传问题
2019-10-31 webUploader大文件断点续传学习心得 多文件
2019-10-31 关于:基于http协议大文件断点续传上传至web服务器