使用NodeJS+Express和aws-sdk直接将文件流式上传到s3

13
我想使用NodeJS通过浏览器直接将一些大文件上传到s3,但是不清楚如何准备这个文件以便上传到s3。可能有更好的模块(比如Knox)来处理这种情况,但我不确定。有什么想法吗?
文件对象
  file: { 
     webkitRelativePath: '',
     lastModifiedDate: '2013-06-22T02:43:54.000Z',
     name: '04-Bro Safari & UFO! - Animal.mp3',
     type: 'audio/mp3',
     size: 11082039 
  }

S3 putObject(S3上传对象)
var params = {Bucket: 'bucket_name/'+req.user._id+'/folder', Key: req.body['file']['name'], Body: ???};
s3.putObject(params, function(err, data) {
    if (err)
      console.log(err);
    else
      console.log("Successfully uploaded data to myBucket/myKey");
});    
5个回答

19

现在支持流式传输(请查看文档),只需将流作为 Body 参数传递即可:

var fs = require('fs');
var someDataStream = fs.createReadStream('bigfile');
var s3 = new AWS.S3({ params: { Bucket: 'myBucket', Key: 'myKey' } });
s3.putObject({ Body: someDataStream, ... }, function(err, data) {
  // handle response
})

5
在上传到S3之前,这是否需要文件存储在硬盘上?我以为OP想跳过保存到硬盘的步骤,直接上传到S3...但是,当涉及到文件上传时,我是一个完全的新手。 - AdamInTheOculus
您可以使用任何流进行上传 - 它不必来自光盘。 - Johann Philipp Strathausen
该方法只能上传较小的文件。为了获得更好的性能和控制,我使用s3.upload() - Ishank
1
请注意,如果您正在从另一个流中进行管道传输,则会收到未知内容长度错误。我建议使用upload,它没有这个问题,并且具有其他优点:https://dev59.com/MVoT5IYBdhLWcg3wjwF-#38442712 - LordParsley

3

s3.putObject()方法不支持流式传输,而且从我看到的情况来看,s3模块也不支持流式传输。然而,使用Knox,您可以使用Client.putStream()进行流式传输。使用您问题中的文件对象,您可以像这样操作:

var fs = require('fs');
var knox = require('knox');

var stream = fs.createReadStream('./file');
var client = knox.createClient({
  key: '<api-key-here>',
  secret: '<secret-here>',
  bucket: 'learnboost'
});

var headers = {
  'Content-Length': file.size,
  'Content-Type': file.type
};

client.putStream(stream, '/path.ext', headers, function(err, res) {
  // error or successful upload
});

谢谢,我知道我的问题有点模糊,因为有很多因素在起作用 - 我有一种感觉Knox是我需要使用的,谢谢。 - Jeff Voss
所以,只是为了明确一下,这将在不先上传文件到 Web 服务器的情况下工作吗?我想完全避免这种情况。 - Jeff Voss
这将把文件流式传输到服务器。与putObject()的主要区别在于,文件不必完全加载到内存中,因此允许您上传非常大的文件。 - hexacyanide
读取流指向本地文件。这是您打算流式传输到服务器的文件。 - hexacyanide
是的,如果我想直接从浏览器上传文件,那么这个文件应该放在哪里? - Jeff Voss
显示剩余5条评论


0

在v3版本中,PutObjectCommand无法将文件流写入S3。我们需要使用@aws-sdk/lib-storage库来上传缓冲区和流。

示例:

const upload = async (fileStream) => {
    const uploadParams = {
        Bucket    : 'test-bucket',
        Key    : 'image1.png',
        Body: fileStream,
    }

    try {
        const parallelUpload = new Upload({
            client: s3Client,
            params: uploadParams,
        });

        console.log('Report progress..')
        parallelUpload.on("httpUploadProgress", (progress) => {
            console.log(progress);
        });

        await parallelUpload.done();
    } catch (e) {
        console.log(e);
    }
}

参考 - https://github.com/aws/aws-sdk-js-v3/blob/main/UPGRADING.md#s3-multipart-upload


0

你的代码没有流式传输。你需要查看是否有调用pipe或者至少使用data事件处理程序手动进行管道传输的代码。你可能正在使用express bodyParser中间件,这不是一个流式实现。它将整个请求体存储为本地文件系统上的临时文件。

我不会提供具体建议,因为我在搜索"node.js s3 stream"时得到了很好的结果。花5分钟阅读一下,然后发布一个至少尝试流式传输的片段,一旦你有了大致的想法,我们可以帮助你正确地完成它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接