import md5 from "@/utils/uploadMD5"; //见上一篇文章封装MD5
import { taskInfoService, initTaskService, mergeUploadService } from "@/api/chunkUploadFile";
const FILE_CHUNKSIZE = 5 * 1024 * 1024;
const BlobSlice =
File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
let failCount = 0;
//定义data
data() {
return {
file: null,
fileMd5: "",
uploadId: "",
fileName: "",
simultaneousUploads: 3, //并发数
uploadPercentage: 0, //上传进度
uploadFail: false, //上传失败
};
}
async fileUpload() {
this.file.chunkList = [];
this.fileMd5 = await md5(this.file, FILE_CHUNKSIZE);
const checkRes = await taskInfoService(this.fileMd5); //检查是否已上传
if (checkRes.code === 100000) {
// 已上传
this.uploadPercentage = 100;
return;
}
if (checkRes.code === 300000) {
// 上传失败
this.uploadFail = false;
return;
}
let fileChunks = this.createFileChunk();
const initTaskData = {
fileMd5: this.fileMd5,
fileName: this.file.name,
fileSize: this.file.size,
chunkSize: FILE_CHUNKSIZE,
partCount: Math.ceil(this.file.size / FILE_CHUNKSIZE),
rtspUrl: this.fileInfo.rtspUrl,
beginTime: this.fileInfo.beginTime,
endTime: this.fileInfo.endTime,
fileType: this.fileInfo.type,
};
if (checkRes.code === 2000000) {
// 断点续传
const uploadedList = checkRes.urlList; //已上传成功的切片列表
uploadedList.forEach((uploaded) => {
let index = this.fileChunks.findIndex((item) => item === uploaded);
if (index !== -1) {
this.fileChunks.splice(index, 1);
}
});
}
// 文件未上传
const initRes = await initTaskService(initTaskData); //获取各切片上传地址
let uploadUrls = initRes.data.urlList;
this.uploadId = initRes.data.uploadId;
this.fileName = initRes.data.fileName;
fileChunks.map((chunkItem, index) => {
this.file.chunkList.push({
chunkNumber: index + 1,
chunk: chunkItem,
uploadUrl: uploadUrls[index],
});
});
// 上传
await this.uploadChunkBase(this.file.chunkList);
// 合并文件
await mergeUploadService({
uploadId: this.uploadId,
fileName: this.fileName,
fileMd5: this.fileMd5,
rtspUrl: this.fileInfo.rtspUrl,
beginTime: this.fileInfo.beginTime,
endTime: this.fileInfo.endTime,
fileType: this.fileInfo.type,
});
}
//各切片上传
uploadChunkBase(chunkList) {
let successCount = 0;
let totalChunks = chunkList.length;
return new Promise((resolve, reject) => {
const handler = () => {
if (chunkList.length) {
const chunkItem = chunkList.shift();
// 直接上传二进制,不需要构造 FormData,否则上传后文件损坏
axios
.put(chunkItem.uploadUrl, chunkItem.chunk.file, {
// 上传进度处理
headers: {
"Content-Type": "application/octet-stream",
},
})
.then((response) => {
if (response.status === 200) {
console.log("分片:" + chunkItem.chunkNumber + " 上传成功");
successCount++;
this.uploadPercentage = (successCount / totalChunks) * 100;
// 继续上传下一个分片
handler();
} else {
console.log(
"上传失败:" + response.status + "," + response.statusText
);
}
})
.catch((error) => {
// 失败后只上传五次,防止卡死
failCount++;
if (failCount < 5) {
// 更新状态
console.log(
"分片:" + chunkItem.chunkNumber + " 上传失败," + error
);
// 重新添加到队列中
chunkList.push(chunkItem);
handler();
} else {
this.$message.error(
"分片:" + chunkItem.chunkNumber + " 上传失败"
);
}
});
}
if (successCount >= totalChunks) {
resolve();
}
};
// 并发 import Queue from 'promise-queue-plus';
for (let i = 0; i < this.simultaneousUploads; i++) {
handler();
}
});
}
// 文件分片
createFileChunk() {
const fileChunkList = [];
let count = 0;
while (count < this.file.size) {
fileChunkList.push({
file: BlobSlice.call(this.file, count, count + FILE_CHUNKSIZE),
});
count += FILE_CHUNKSIZE;
}
return fileChunkList;
}
文件分片上传
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 上传管理 上传列表 网络变化处理 关于网络变化的处理,主要是对4G情况的处理,代码如下: 上传完成列表 支持文件名...
- 前端使用UI封装好的upload组件 1.单文件上传 2.多文件上传 3.分片上传(使用blob切片对文件进行切割...
- 在实际的业务场景中,很多时候都需要对App进行更新,最近就遇到这样的一个需求,在App端有个检查更新的功能,如果发...
- 1. 组件简介 webuploader:是一个以HTML5为主, Flash为辅的文件上传组件,采用大文件分片/并...
- 1. 简介: 本篇文章基于实际项目的开发,将介绍项目中关于大文件分片上传、文件验证、断点续传、手动重试上传等需求的...