Skip to content
On this page

在上传的时候,如果文件过大,很容易因为网络等原因上传失败,即使已经上传了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);
    }
  }

Released under the MIT License.