如何通过 client-side JavaScript 将任何类型的文件上传到 S3 存储桶?

How to upload any type of file to an S3 bucket via client-side JavaScript?

我在通过 FileReader 读取文件并通过 PutObject 将其正确上传到 S3 且文件未损坏时遇到问题。

问题描述

我一直在使用 MongoDB Stitch 作为我的应用程序的无服务器平台,它 built-in 带有 S3 服务提供商。我可以正确上传文本文件,但如果我尝试上传任何二进制文件(Excel、PDF、图像等)并直接从我的 S3 存储桶下载它并在其各自的程序中打开它,我的电脑会报告它已损坏。

我查看了两个文件,我电脑上的原始文件和上传到 S3 的文件,它们非常相似,但似乎在上传过程中更改了一些数据。

当前尝试

我正在使用 FileReader 打开阅读流并使用 FileReader.readAsBinaryString() 阅读文件。我在 headers 中的 ContentType 通过 File.type.

我看到 W3C 建议使用 FileReader.readAsArrayBuffer() 而不是 readAsBinaryString(),但是 S3 在尝试上传结果数据时报告错误:value for field "Body" should be of type "io.ReadSeeker".

我也试过 FileReader.readAsDataURL(),但我不知道有什么方法可以将 any 文件类型的 base64 URL 转换回它的原始格式。我能找到的唯一例子都涉及使用 base64 到 encode/decode 图像。

代码

const readFile = (file) => {

  return new Promise((resolve) => {

    const fileReader = new FileReader()
    fileReader.onload = (event) => {
      resolve(event.target.result)
    }
    fileReader.readAsBinaryString(file)

  })

}

async s3Upload(file) {

  const fileData = await readFile(file)

  const putObjectArgs = {
    Body: fileData,
    Key: file.name,
    ContentType: file.type,
    ACL: 'public-read',
    Bucket: 'BUCKET_NAME',
  }

  // call the Stitch services to upload

}

问题

有没有办法将任何类型的文件上传到 S3,就像它存储在我的文件系统中一样?或 encode/decode 任何文件类型 to/from base64?

的通用方法

我找到了 FilePond 和类似的库,因为它支持任何类型的服务器上传,所以我决定使用它而不是尝试自己创建文件上传逻辑。

更新:

甚至 FilePond 都让您定义自己的 AWS 上传逻辑...但我终于想通了。

使用 MongoDB Stitch 时,您必须将 ArrayBuffer 转换为 UInt8Array,然后使用其 SDK 将其转换为 BSON 二进制类型。这是代码:

const reader = new FileReader()

reader.onload = (e) => {
  const fileData = new Uint8Array(reader.result)
  const fileBson = new BSON.Binary(fileData)

  // upload to S3
  // ...
}

reader.readAsArrayBuffer(file)