Node JS - 将数据从Busboy传输到AWS S3

时间:2016-04-28 09:52:43

标签: node.js amazon-web-services amazon-s3 amazon-ec2 busboy

我正在尝试通过ec2将文件上传到s3。 我的第一个方法是 - 将文件完全上传到ec2,然后将该文件上传到s3。这种方法并不好,因为从ec2到s3的转移时间是浪费时间。

目前我正在尝试使用 busboy上传流 s3上传流,以便上传到ec2,然后再上传到ec3到s3,因为s3 上传“方法支持流作为上传正文。

这是我的代码 -

router.post('/s3StreamUpload', function(req, res, next) {
   var busboy = new Busboy({headers: req.headers});
   busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
      console.log('Before Upload: ' + new Date());
      console.log('File [' + fieldname + ']: filename: ' + filename + ', encoding: ' + encoding + ', mimetype: ' + mimetype);

      var s3 = new AWS.S3({
         params: {Bucket: 'sswa', Key: filename, Body: file},
         options: {partSize: 5 * 1024 * 1024, queueSize: 10}   // 5 MB
      });
      s3.upload().on('httpUploadProgress', function (evt) {
         console.log(evt);
      }).send(function (err, data) {
         console.log('After Upload: ' + new Date());
         console.log(err, data);
      });
   });
   busboy.on('field', function(fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) {
      console.log('Field [' + fieldname + ']: value: ' + inspect(val));
   });
   busboy.on('finish', function() {
      console.log('Done parsing form!');
      res.writeHead(303, { Connection: 'close', Location: '/' });
      res.end();
   });
   req.pipe(busboy);
});

我怀疑它是否真的像流一样上传到s3?这种方法有什么缺点吗?

2 个答案:

答案 0 :(得分:1)

为了测试上传到S3的多部分流式传输是否有效,我花时间记录了三个执行点 -

  1. 从客户端开始上传之前( uploadStartTime
  2. 上传至EC2( busboyFinishTime
  3. 转入S3后( s3UploadFinishTime
  4. 然后我从EC2开始。在上传了各种长度的视频文件(36.1 MB,33.3 MB,52.5 MB)后,我观察到,每上传到EC2的5MB(如我所定义),部件立即转移到S3。将零件上传到S3时,您将看到以下行的日志。它将显示文件部件上传进度和部件号。

    console.log(evt);
    

    对于所有三个上传 busboyFinishTime s3UploadFinishTime 相同或几乎没有1秒的差异。

    实施例: 当52.5 MB上传时

    {
      "uploadStartTime": "2016-04-28T14:19:51.365Z",
      "busboyFinishTime": "2016-04-28T14:22:26.292Z",
      "s3UploadFinishTime": "2016-04-28T14:22:26.558Z"
    }
    

    完整代码:

    router.post('/s3StreamUpload', function(req, res, next) {
       var busboy = new Busboy({headers: req.headers});
       var uploadStartTime = new Date(),
          busboyFinishTime = null,
          s3UploadFinishTime = null;
    
       busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
          console.log('File [' + fieldname + ']: filename: ' + filename + ', encoding: ' + encoding + ', mimetype: ' + mimetype);
    
          var s3 = new AWS.S3({
             params: {Bucket: 'sswa', Key: filename, Body: file},
             options: {partSize: 5 * 1024 * 1024, queueSize: 10}   // 5 MB
          });
          s3.upload().on('httpUploadProgress', function (evt) {
             console.log(evt);
          }).send(function (err, data) {
             s3UploadFinishTime = new Date();
             if(busboyFinishTime && s3UploadFinishTime) {
                res.json({
                   uploadStartTime: uploadStartTime,
                   busboyFinishTime: busboyFinishTime,
                   s3UploadFinishTime: s3UploadFinishTime
                });
             }
             console.log(err, data);
          });
       });
       busboy.on('field', function(fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) {
          console.log('Field [' + fieldname + ']: value: ' + inspect(val));
       });
       busboy.on('finish', function() {
          console.log('Done parsing form!');
          busboyFinishTime = new Date();
          if(busboyFinishTime && s3UploadFinishTime) {
             res.json({
                uploadStartTime: uploadStartTime,
                busboyFinishTime: busboyFinishTime,
                s3UploadFinishTime: s3UploadFinishTime
             });
          }
       });
       req.pipe(busboy);
    });
    

    根据我的观察,我确信这是使用部署在EC2上的REST API通过EC2将文件上传到S3的最佳解决方案之一。

答案 1 :(得分:0)

您是否尝试直接从浏览器上传到S3?如果是这样,您可以使用presigned-put直接浏览到S3上传。

这是使用minio-js

生成预先签名的PUT网址的方法
s3Client.presignedPutObject('my-bucketname', 'my-objectname', 1000, function(e, presignedUrl) {
  if (e) return console.log(e)
  console.log(presignedUrl)
})

现在您将此预签名URL传递给浏览器客户端,该客户端可以使用XMLHttpRequest将文件直接输入S3。