从 Web 浏览器分部分上传到 Amazon S3

Luk*_*uke 3 asp.net-mvc jquery amazon-s3 amazon-web-services plupload

我们目前有一个小型网络应用程序,其中一部分是文件上传。目前,我们在客户端上使用 Plupload,启用分块以允许上传大文件。文件保存在应用程序服务器上,并且块在出现时附加。

现在我们正在迁移到 Amazon S3。任何人都可以分享一些关于如何在 s3 上分块上传文件的示例吗?我尝试使用它正在上传的 Presinged url,但限制只有 5 GB 。

All*_*hua 7

您必须结合使用分段上传和 S3 签名 URL。

基本上,步骤是:

  1. 在后端启动分段上传
  const params = {
    Bucket: BUCKET_NAME,
    Key: OBJECT_NAME
  }

  const res = await s3.createMultipartUpload(params).promise()

  return res.UploadId
Run Code Online (Sandbox Code Playgroud)
  1. 为每个块创建预签名 URL(API 级别)

async function generatePresignedUrlsParts(s3: AWS.S3, uploadId: string, parts: number) {
  const baseParams = {
    Bucket: BUCKET_NAME,
    Key: OBJECT_NAME,
    UploadId: uploadId
  }

  const promises = []

  for (let index = 0; index < parts; index++) {
    promises.push(
      s3.getSignedUrlPromise('uploadPart', {
      ...baseParams,
      PartNumber: index + 1
    }))
  }

  const res = await Promise.all(promises)

  return res.reduce((map, part, index) => {
    map[index] = part
    return map
  }, {} as Record<number, string>)
}
Run Code Online (Sandbox Code Playgroud)
  1. 上传每个块
import Axios from 'axios'

interface Part {
  ETag: string
  PartNumber: number
}

const FILE_CHUNK_SIZE = 10_000_000

async function uploadParts(file: Buffer, urls: Record<number, string>) {
  const axios = Axios.create()
  delete axios.defaults.headers.put['Content-Type']

  const keys = Object.keys(urls)
  const promises = []

  for (const indexStr of keys) {
    const index = parseInt(indexStr)
    const start = index * FILE_CHUNK_SIZE
    const end = (index + 1) * FILE_CHUNK_SIZE
    const blob = index < keys.length
      ? file.slice(start, end)
      : file.slice(start)

    promises.push(axios.put(urls[index], blob))
  }

  const resParts = await Promise.all(promises)

  return resParts.map((part, index) => ({
    ETag: (part as any).headers.etag,
    PartNumber: index + 1
  }))
}
Run Code Online (Sandbox Code Playgroud)
  1. 完成分段上传
interface Part {
  ETag: string
  PartNumber: number
}

async function completeMultiUpload(uploadId: string, parts: Part[]) {
  const s3 = new AWS.S3({
    accessKeyId: /* Bucket owner access key id */,
    secretAccessKey: /* Bucket owner secret */,
    sessionToken: `session-${cuid()}`
  })

  const params = {
    Bucket: BUCKET_NAME,
    Key: OBJECT_NAME,
    UploadId: uploadId,
    MultipartUpload: { Parts: parts }
  }

  await s3.completeMultipartUpload(params).promise()
}
Run Code Online (Sandbox Code Playgroud)