需求背景:
前端上传视频,有时候视频动不动就上百兆甚至1个G,如果用传统的input提交表单方式选择文件调后台接口上传,那很有可能出现:
文件过大,超出服务端的请求大小限制;
请求时间过长,请求超时;
传输中断,必须重新上传导致前功尽弃;
等各种问题,整个上传过程耗时漫长。
由此我们可以采用前端分片的方案,当然这还需要后台接口的支持,后台得接收分片并正确组合(后台组合的好处在于一旦上传中断不用全部重新上传只要找到那个中断的分片就好,节约成本。),具体就不在这说了。
解决方案一:
html部分采用el-upload组件,具体代码如下:
<el-upload
class="upload-demo"
action="https://jsonplaceholder.typicode.com/posts/"
:on-change="handleChange"
:http-request="putinMirror"
:file-list="fileList">
<el-button size="small" type="primary">点击上传</el-button>
<!-- <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div> -->
</el-upload>
js部分代码如下:
export default {
name: "JsPage",
data() {
return {
fileList: [{
name: 'food.jpeg',
url: ''
}, {
name: 'food2.jpeg',
url: ''
}]
}
},
mounted() {},
methods: {
handleChange(file, fileList) {
console.log('文件上传change事件:',file, fileList)
//this.fileList = fileList.slice(-3);
},
// 覆盖组件默认的上传行为,可以自定义上传的实现
async putinMirror(file) {
// 每个文件切片大小定为5MB
let sliceSize = 0.5 * 1024 * 1024;
// 文件大小限制为最大1个G,可根据需求修改
let maxfilesizes = 1 * 1024 * 1024 * 1024;
console.log('putinMirror:',file)
const blob = file.file;
const fileSize = blob.size;// 文件大小
const fileName = blob.name;// 文件名
//计算文件切片总数,Math.ceil向上取整数
const totalSlice = Math.ceil(fileSize / sliceSize);
console.log('当前上传文件的详情信息',blob,totalSlice,fileSize / sliceSize)
if(fileSize <= maxfilesizes){
// 循环上传
for (let i = 0; i < totalSlice; i++) {
let start = i * sliceSize;
let chunk = blob.slice(start, Math.min(fileSize, start + sliceSize));
console.log('每个切片的信息:',chunk)
const formData = new FormData();
formData.append("file", chunk);
formData.append("signal", blob.uid);
formData.append("name", fileName);
formData.append("size", fileSize);
formData.append("chunks", totalSlice);
formData.append("chunk", i+1);
let res = await this.uploadExcleAndZip(formData);//uploadExcleAndZip模拟接口上传,一个分片上传完成后再调用接口上传下一片
console.log(res);
if(res.errCode == 0){
//this.progress = ((i+1)/totalSlice).toFixed(1) * 100;//控制进度条
setTimeout(()=>{
if((i+1) == totalSlice){
this.$message({
message: '上传成功',
type: 'success'
});
}
}, 1000);
}
}
} else { // 文件大小超出最大限制
this.$message({
message: '文件大小超出1G',
type: 'error'
});
}
},
uploadExcleAndZip(formData) {
console.log('在这里模拟调接口:',formData)
return {
errCode:0
}
}
}
}
注意:每个分片的大小不宜过大,一般5M左右。
点上传效果图如下: