我需要将一个文件从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线程中建议的那样。
这段代码保持不变,有趣的是 uploadToFirstS3
和 uploadToSecondS3
函数。在这个最小化的例子中,它们都用不同的配置做着完全相同的事情,我只会在这里扩展一个。
良好的工作原理:
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 - 未实现错误,其中包含头
Transfer-Encoding
。我检查了req.headers
,里面没有Transfer-Encoding
,所以我猜sdk会在请求中添加吗?既然第一个基于aws-sdk的例子运行良好,我确定错误不是由请求中的空主体导致的,就像这个SO线程中建议的那样。
尽管如此,我想也许当触发上传时,流还没有准备好读取,因此我使用回调函数将对
uploadToFirstS3
和uploadToSecondS3
的调用包装在req.on('readable', callback)
事件触发的回调中,但是什么也没有改变。我想在内存中处理文件,而不必在任何时候将其存储在磁盘上。有没有办法使用@aws-sdk/client-s3包实现这一点?
new S3({}) || new S3Client({})
? - Can RauS3Client
使其工作,所以我将更新示例以使用它。 - Andynew S3({})
总是真值。也许他们试图说明您可以使用任何一个(不确定是否可以?),但这将是一种语义上奇怪的方式。 - AndyparallelUploads3.on("httpUploadProgress" ....
这一行,流式上传将无法开始/完成;如何在不侦听httpUploadProgress
和不打印进度的情况下启动或完成流式上传? - Kid_Learning_C