此代码为写项目中遇到的,需要的可以直接复制参考使用。
上传视频时因视频文件过大,所以需要使用分片来进行上传并MD5校验,改到前端校验后在上传,同时改为切片上传,
需要使用md5对文件的临时文件内容加密,和后端的文件相互验证文件
第一步:md5下载
npm install spark-md5
第二步:引入md5
import SparkMD5 from "spark-md5";
第三步:计算文件的MD5值 ,直接上代码
const generateMd5 = (file) => {
console.log("fileMD5", file);
return new Promise((resolve, reject) => {
const chunkSize = 1024 * 1024; // 1MB 分块读取文件
const blobSlice =
File.prototype.slice ||
File.prototype.mozSlice ||
File.prototype.webkitSlice;
const chunks = Math.ceil(file.size / chunkSize);
let currentChunk = 0;
const spark = new SparkMD5.ArrayBuffer();
const fileReader = new FileReader();
fileReader.onload = function (e) {
spark.append(e.target.result); // append array buffer
currentChunk++;
if (currentChunk < chunks) {
loadNext();
} else {
resolve(spark.end());
}
};
fileReader.onerror = function (err) {
reject(err);
};
function loadNext() {
const start = currentChunk * chunkSize;
const end =
start + chunkSize >= file.size ? file.size : start + chunkSize;
fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
}
loadNext();
});
};
用的是element-plus中的el-upload,因为我是上传视频,所以直接设置accept为:video/*,
进度条用的是:el-progress, 代码如下:
<el-form-item label="用户视频素材" prop="saved_path">
<el-upload
class="upload-demo"
drag
accept="video/*"
:onChange="changeUpload"
:before-upload="handleBeforeVideoUpload"
action="#"
multiple
:file-list="fileList"
>
<div v-if="uploadVideoTip == ''">
<el-icon class="el-icon--upload">
<Plus />
</el-icon>
<div class="el-upload__text">点击+号上传或将文件拖拽到框内</div>
</div>
<div v-else><el-button>继续上传</el-button></div>
<template #tip>
<div
class="el-upload__tip"
style="display: flex; align-item: center"
>
<span v-if="uploadVideoTip == ''"> *每个大小不得超过1G</span>
<span v-else>
<el-scrollbar height="40vh">
<div v-for="(item, index) in videoFiles" :key="index">
{{ item.name }}
<img
src="../assets/img/取消.png"
alt=""
@click="delImg(item)"
/>
<el-icon
v-if="item.uploaded"
style="color: #24b023; font-size: 20px"
><Check
/></el-icon>
</div>
</el-scrollbar>
</span>
</div>
</template>
</el-upload>
<el-progress :percentage="progress" v-show="progress > 0" />
</el-form-item>
上传视频时,先通过判断文件是否大于20M,如果小于20则正常上传,如果大于20则进行分片来上传,并且MD5是加密切割之前的文件 ,代码如下:
const progress = ref(0); //视频进度
const changeUpload = async (file) => {
console.log("视频上传file ", file);
let { name, size, raw: uploadfile } = file;
let chunkSize = 5 * 1024 * 1024; //默认每个分片为5M
// 生成的md5值························································
let md5FileName = await generateMd5(uploadfile);
//通过判断视频文件,如果大于20M则进行分片,代码如下:
if (size <= 20 * 1024 * 1024) {
// 文件小于20M
let formData = new FormData();
formData.append("block_id", 1); //默认为1
formData.append("block_total", 1); //默认为1
formData.append("saved_path", uploadfile);//视频文件
formData.append("md5_file_name", md5FileName); //MD5内容加密
formData.append("saved_path_name", name); //文件名
agentsUploadsApi(formData).then((res) => {
console.log("上传res", res.data.data);
if (res.status !== 200) {
return;
} else {
if (res.data.code == 0) {
let ids = res.data.data;
if (ids.result.id) {
ElMessage({
message: "上传成功,请提交",
type: "success",
});
}
} else {
ElMessage({
message: res.data.msg,
type: "error",
});
}
}
});
} else {
// 文件大于20M
let chunkList = [], startSize = 0;
while (startSize < size) {
let endSize = Math.min(size, startSize + chunkSize);
chunkList.push(uploadfile.slice(startSize, endSize));
startSize += chunkSize;
}
for (let index = 0; index < chunkList.length; index++) {
let chunk = chunkList[index];
console.log("分片Blob文件", chunk);
// 如果分片传入要的是File格式的话,就复制下面注释的这个代码,传splitFile
// let blob = new Blob([chunk], { type: uploadfile.type });
// // 创建新的 File 对象来表示分片,包含文件的后缀名
// let splitFile = new File(
// [blob],
// name.slice(0, name.lastIndexOf(".")) +
// index +
// name.slice(name.lastIndexOf(".")),
// { type: uploadfile.type }
// );
let formData = new FormData();
formData.append("block_id", index + 1); //当前上传的第几块
formData.append("block_total", chunkList.length);//总分片数
formData.append("saved_path", chunk); //将分片传入 这是blob格式
formData.append("md5_file_name", md5FileName); //MD5内容加密
formData.append("saved_path_name", name); //文件名
//调取接口 上传为异步并使用await等待其完成
let response = await agentsUploadsApi(formData);
console.log("上传res", response.data.data);
if (response.status !== 200) {
return;
}
if (response.data.code == 0) {
let ids = response.data.data;
if (ids.result.id) {
ElMessage({
message: "上传成功,请提交",
type: "success",
});
}
progress.value = Math.round(((index + 1) / chunkList.length) * 100);//视频上传进度
} else {
ElMessage({
message: response.data.msg,
type: "error",
});
}
}
}
};