簡體   English   中英

如何使用 AWS SDK v3 將流上傳到 S3

[英]How to upload a stream to S3 with AWS SDK v3

我必須將文件從 API 端點傳輸到兩個不同的存儲桶。 原始上傳是使用:

curl -X PUT -F "data=@sample" "http://localhost:3000/upload/1/1"

上傳文件的端點:

const PassThrough = require('stream').PassThrough;

async function uploadFile (req, res) {
  try {
    const firstS3Stream = new PassThrough();
    const secondS3Stream = new PassThrough();
    req.pipe(firstS3Stream);
    req.pipe(secondS3Stream);

    await Promise.all([
      uploadToFirstS3(firstS3Stream),
      uploadToSecondS3(secondS3Stream),
    ]);
    return res.end();
  } catch (err) {
    console.log(err)
    return res.status(500).send({ error: 'Unexpected error during file upload' });
  }
}

如您所見,我使用了兩個PassThrough流,以便將請求流復制到兩個可讀流中, 如此 SO thread 中所建議的。

這段代碼保持不變,這里有趣的是uploadToFirstS3uploadToSecondS3函數。 在這個最小的例子中,兩者都用不同的配置做完全相同的事情,我在這里只用一個。

什么效果好:

const aws = require('aws-sdk');

const s3 = new aws.S3({
  accessKeyId: S3_API_KEY,
  secretAccessKey: S3_API_SECRET,
  region: S3_REGION,
  signatureVersion: 'v4',
});

const uploadToFirstS3 = (stream) => (new Promise((resolve, reject) => {
  const uploadParams = {
    Bucket: S3_BUCKET_NAME,
    Key: 'some-key',
    Body: stream,
  };
  s3.upload(uploadParams, (err) => {
    if (err) reject(err);
    resolve(true);
  });
}));

這段代碼(基於aws-sdk包)工作正常。 我的問題是我希望它與@aws-sdk/client-s3包一起運行以減小項目的大小。

什么不起作用:

我首先嘗試使用S3Client.send(PutObjectCommand)

const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');

const s3 = new S3Client({
  credentials: {
    accessKeyId: S3_API_KEY,
    secretAccessKey: S3_API_SECRET,
  },
  region: S3_REGION,
  signatureVersion: 'v4',
});

const uploadToFirstS3 = (stream) => (new Promise((resolve, reject) => {
  const uploadParams = {
    Bucket: S3_BUCKET_NAME,
    Key:'some-key',
    Body: stream,
  };
  s3.send(new PutObjectCommand(uploadParams), (err) => {
    if (err) reject(err);
    resolve(true);
  });
}));

然后我嘗試了S3.putObject(PutObjectCommandInput)

const { S3 } = require('@aws-sdk/client-s3');

const s3 = new S3({
  credentials: {
    accessKeyId: S3_API_KEY,
    secretAccessKey: S3_API_SECRET,
  },
  region: S3_REGION,
  signatureVersion: 'v4',
});

const uploadToFirstS3 = (stream) => (new Promise((resolve, reject) => {
  const uploadParams = {
    Bucket: S3_BUCKET_NAME,
    Key:'some-key',
    Body: stream,
  };
  s3.putObject(uploadParams, (err) => {
    if (err) reject(err);
    resolve(true);
  });
}));

最后兩個示例都給我一個501 - Not Implemented錯誤,標題為Transfer-Encoding 我檢查了req.headers並且其中沒有Transfer-Encoding ,所以我猜 sdk 將請求添加到 s3 ?

由於第一個示例(基於aws-sdk )工作正常,我確定該錯誤不是由於請求中的空正文引起的,如該 SO thread 中建議的那樣。

盡管如此,我認為在觸發上傳時流可能還不可讀,因此我用req.on('readable', callback)事件觸發的回調封裝了對uploadToFirstS3uploadToSecondS3的調用,但沒有任何改變。

我想處理內存中的文件,而不是隨時將其存儲在磁盤上。 有沒有辦法使用@aws-sdk/client-s3包來實現它?

在 S3 中,您可以使用來自@aws-sdk/lib-storageUpload類進行分段上傳。 不幸的是, @aws-sdk/client-s3的文檔站點中似乎沒有提到這一點。

它在此處的升級指南中提到: https : //github.com/aws/aws-sdk-js-v3/blob/main/UPGRADING.md#s3-multipart-upload

這是https://github.com/aws/aws-sdk-js-v3/tree/main/lib/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);
  }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM