Appearance
在上传的时候,如果文件过大,很容易因为网络等原因上传失败,即使已经上传了99%一旦失败就需要重新开始上传了,这个时候就需要用到分片上传了。 分片上传顾名思义就是就文件切成一片片的,然后再循环上传,这样每次上传的内容就比较小了。而且如果某一片上传失败了,只需要重新上传这一片就行了。
前端进行文件切片
1、在拿到上传文件对象后(一般时blob对象),利用数组的slice方法,将文件切割成多个文件块
// 获取文件内容
let file=e.target.files[0]
let chunkSize=1*1024*1024,//设置按1M来分片
// 总共分chunkNums片
let chunkNums=Math,ceil(file.size/chunkSize)
2、将切割好的每一片文件进行上传
const {name,size}=file
let uploadedSize=0
for(let i=0;i<chunkNums;i++){
let start=i*chunkSize
let end=(start+chunkSize)>size?size:start+chunkSize
let chunkFile=file.slice(start,end)
const fd=new FormData()
fd.append('name',name)
fd.append('size',size)
fd.append('uploadedSize',uploadedSize)
try {
await axios.post('/api/upload',fd)
uploadedSize+=chunkSize
}catch(err){
console.log(err)
}
}
3、何时通知服务端合并文件 方式1:在分片上传完成以后再发送一个合并文件的请求(不推荐) 方式2:在分片上传的时候,可以额外发送一个字段uploadedSize,表示已经上传过的文件大小,这样服务端就可以通过uploadedSize和文件的size来判断是否已经上传完成了。
服务端进行文件合并
这里以nestjs为例,express和koa类似
// 分片上传
@Post('chunk')
@UseInterceptors(FileInterceptor('file'))
chunkUpload(@UploadedFile() file, @Body() body) {
const { name, size, totalSize, uploadedSize } = body;
if (!file) {
return '文件不存在';
}
let filePath = join(__dirname, '../../uploads', name);
console.log(filePath);
if (uploadedSize != 0) {
// 开始合并文件
// 1、判断文件是否存在
if (!existsSync(filePath)) {
console.log('文件不存在');
return;
}
appendFileSync(filePath, file.buffer);
return {
code: 0,
msg: '上传成功',
data: `http://localhost:3000/${name}`,
};
} else {
writeFileSync(filePath, file.buffer);
}
}