【问题标题】:aws sdk Multipart Upload to s3 with node.jsaws sdk 使用 node.js 分段上传到 s3
【发布时间】:2021-06-13 19:34:49
【问题描述】:

我正在尝试使用 node.js aws-sdk 将大文件上传到 s3 存储桶。

V2 方法 upload分段上传的方式整体上传文件。

我想使用新的 V3 aws-sdk。新版本上传大文件的方法是什么?方法PutObjectCommand 好像不行。

我看到有诸如 CreateMultiPartUpload 之类的方法,但我似乎找不到使用它们的完整工作示例。

提前致谢。

【问题讨论】:

    标签: node.js amazon-web-services amazon-s3 aws-sdk aws-sdk-nodejs


    【解决方案1】:

    截至 2021 年,我建议使用 lib-storage 包,它抽象了很多实现细节。

    示例代码:

    import { Upload } from "@aws-sdk/lib-storage";
    import { S3Client, S3 } from "@aws-sdk/client-s3";
    
    const target = { Bucket, Key, Body };
    try {
      const parallelUploads3 = new Upload({
        client: new S3({}) || new S3Client({}),
        tags: [...], // optional tags
        queueSize: 4, // optional concurrency configuration
        partSize: 5MB, // optional size of each part
        leavePartsOnError: false, // optional manually handle dropped parts
        params: target,
      });
    
      parallelUploads3.on("httpUploadProgress", (progress) => {
        console.log(progress);
      });
    
      await parallelUploads3.done();
    } catch (e) {
      console.log(e);
    }
    

    来源:https://github.com/aws/aws-sdk-js-v3/blob/main/lib/lib-storage/README.md

    【讨论】:

    • 由于某种原因,我的应用程序的内存只会随着这种方法而增加。我找不到如何以良好且高效的方式使用 v3。
    • 到目前为止,我在使用这种方法时获得了很好的体验。感谢您的回答。
    【解决方案2】:

    这是我想出的,将 Buffer 上传为分段上传,使用适用于 nodejs 和 TypeScript 的 aws-sdk v3。

    错误处理仍然需要一些工作(您可能希望在发生错误时中止/重试),但这应该是一个很好的起点......我已经用最大 15MB 的 XML 文件对此进行了测试,到目前为止好的。不过没有保证! ;)

    import {
      CompleteMultipartUploadCommand,
      CompleteMultipartUploadCommandInput,
      CreateMultipartUploadCommand,
      CreateMultipartUploadCommandInput,
      S3Client,
      UploadPartCommand,
      UploadPartCommandInput
    } from '@aws-sdk/client-s3'
    
    const client = new S3Client({ region: 'us-west-2' })
    
    export const uploadMultiPartObject = async (file: Buffer, createParams: CreateMultipartUploadCommandInput): Promise<void> => {
      try {
        const createUploadResponse = await client.send(
          new CreateMultipartUploadCommand(createParams)
        )
        const { Bucket, Key } = createParams
        const { UploadId } = createUploadResponse
        console.log('Upload initiated. Upload ID: ', UploadId)
    
        // 5MB is the minimum part size
        // Last part can be any size (no min.)
        // Single part is treated as last part (no min.)
        const partSize = (1024 * 1024) * 5 // 5MB
        const fileSize = file.length
        const numParts = Math.ceil(fileSize / partSize)
    
        const uploadedParts = []
        let remainingBytes = fileSize
    
        for (let i = 1; i <= numParts; i ++) {
          let startOfPart = fileSize - remainingBytes
          let endOfPart = Math.min(partSize, startOfPart + remainingBytes)
    
          if (i > 1) {
            endOfPart = startOfPart + Math.min(partSize, remainingBytes)
            startOfPart += 1
          }
    
          const uploadParams: UploadPartCommandInput = {
            // add 1 to endOfPart due to slice end being non-inclusive
            Body: file.slice(startOfPart, endOfPart + 1),
            Bucket,
            Key,
            UploadId,
            PartNumber: i
          }
          const uploadPartResponse = await client.send(new UploadPartCommand(uploadParams))
          console.log(`Part #${i} uploaded. ETag: `, uploadPartResponse.ETag)
    
          remainingBytes -= Math.min(partSize, remainingBytes)
    
          // For each part upload, you must record the part number and the ETag value.
          // You must include these values in the subsequent request to complete the multipart upload.
          // https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html
          uploadedParts.push({ PartNumber: i, ETag: uploadPartResponse.ETag })
        }
    
        const completeParams: CompleteMultipartUploadCommandInput = {
          Bucket,
          Key,
          UploadId,
          MultipartUpload: {
            Parts: uploadedParts
          }
        }
        console.log('Completing upload...')
        const completeData = await client.send(new CompleteMultipartUploadCommand(completeParams))
        console.log('Upload complete: ', completeData.Key, '\n---')
      } catch(e) {
        throw e
      }
    }
    
    

    【讨论】:

    • 感谢您的回复。不幸的是,我遇到了同样的 MalformedXML 错误。此外,当我运行您的代码时,我仍然会为每个部分获得相同的 ETag
    • 其实除了第一个和最后一个之外,所有的ETag都是一样的。
    猜你喜欢
    • 2021-06-13
    • 2018-04-25
    • 2020-04-18
    • 2016-02-07
    • 2017-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-10
    相关资源
    最近更新 更多