大文件上传

6,797 阅读1分钟

如何上传 10GB 左右的视频文件?

如果通过以前的二进制上传方式,将它一次性上传将会产生一系列问题。

  1. Request Body 过大,在上传 9GB 左右失败时,需要重新全部上传,浪费时间
  2. Request Body 过大,导致时间过长

既然上传整个视频文件过大,那将它分割成 N 个小块上传,服务器端再将其进行拼接,岂不是可以解决问题?

上传效果可在 Apifox 查看:

image.png

客户端分割

资源分为二进制资源与文本资源,文本资源很容易被分割与拼接,那二进制资源呢?

我们在浏览器端上传二进制资源时,通过 Blob 进行上传,可使用 Blob.prototype.slice 进行切片。

const blob = instanceOfBlob.slice([start [, end [, contentType]]]}

通过 createChunks 函数可创建分片,并通过 uploadChunks 上传分片,在所有分片上传完成之后发送请求通知服务端进行切片合并。

function createChunks(blob, chunkSize) {
  const chunks = []
  let id = 0
  while (start < blob.size) {
    chunks.push({
      blob: blob.slice(id * chunkSize, (id + 1) * chunkSize),
      id: id
    })
    id++
  }
  return chunks
}

async function uploadChunks(chunks) {
  for (const chunk of chunks) {
    const form = new FormData()
    form.append('blob', chunk.blob)
    form.append('id', chunk.id)
    
    // 分片上传大文件
    await fetch('/upload-bigfile', {
      body: form
    })
  }
  // 全部分片上传完成之后,可以通知服务器端合并所有分片
  await fetch('/upload-bigfile/merge')
}

在上传切片的过程中,为了保证上传速度,可通过 p-map 控制并发上传。

上传效果可在 Apifox 查看:

image.png

服务器拼接

作业

  1. 如何实现大文件上传