js大文件切片上传,断点续传实现demo
思路
- 把大文件切成每块10M(按照你自己的要求),然后依次上传(为了让你好理解,你可以理解成分页,一共89条数据,每页数10条,一共9页)。
- 上传完成后端把文件封装好,返回上传的url地址
- 加上进度条
- 中途上传中断,如果再次上传如何回到原来的位置继续上传,解决办法就是每次上传前给后端请求接口查验下,该文件上传到第几片了,和后端对接好chunk参数,比如-1代表已经上传完,0代表第0片,以此类推。
- 完善各种情况:比如发生错误,是否可以尝试重新上传,离开页面以后取消上传操作(离开页面以后,上传还在继续,这种情况除了上传还有计时器的问题,这里就不多说了,总之离开之前先清掉的思路)
PS:一定要上传完一个才能上传完下一个,是串行不是并行,另外,ajax一定要是异步的不管是原生还是jq的ajax,因为我开始弄成同步,progress事件根本出不来
我做这个的最大感悟就是一点点做起来的一个完善的东西,都是在开发中不断完善的,一开始不会考虑到那么多情况,或者你先不要考虑那么多,先把基础做了,慢慢叠加功能。我是先把1和2做了以后才慢慢加上3、4、5,这是一个很自然的过程,如果你一上来都要实现,对我而言亚历山大。
后台需要提供三个接口:
- 上传文件的接口
- 上传之前查验文件是否上传过,上传到第几片的接口
- 上传文件完成merge的接口
完整代码一:vue版本
(vue+js+ajax+md5+element-ui)
<input id="file" name="file" type="file"/>
<el-button size="small" type="primary" id="startBtn">上传视频</el-button>
<div>
<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>
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