使用AWS-SDK将流式上传的经过GM调整大小的图像上传到S3

16

我想做的是从URL流式传输一张图片,使用GraphicsMagick处理它并将其流式上传到S3。但我无法让它正常工作。

将处理后的图像流式传输到本地磁盘(使用fs.createWriteStream)没有问题。

当我缓冲我的流时,S3中的最终图像至少具有预期的大小(以KB为单位),但我无法打开该图像。

这是我的当前进展:

var request = require('request');

var gm = require("gm");

var AWS = require('aws-sdk');

var mime = require('mime');

var s3 = new AWS.S3();

gm(request('http://www.some-domain.com/some-image.jpg'), "my-image.jpg")
  .resize("100^", "100^")
  .stream(function(err, stdout, stderr) {
    var str = '';
    stdout.on('data', function(data) {
       str += data;
    });
    stdout.on('end', function(data) {
      var data = {
        Bucket: "my-bucket",
        Key: "my-image.jpg",
        Body: new Buffer(str, 'binary'), // thats where im probably wrong
        ContentType: mime.lookup("my-image.jpg")
      };
      s3.client.putObject(data, function(err, res) {
        console.log("done");
      });
    });
  });

我尝试了一些方法,比如创建一个FileWriteStream和FileReadStream,但是我认为应该有更简洁优雅的解决方案来解决这个问题...

编辑:我尝试的第一件事是将Body设置为stdout(@AndyD建议的答案):

var data = {
    Bucket: "my-bucket",
    Key: "my-image.jpg",
    Body: stdout,
    ContentType: mime.lookup("my-image.jpg")
  };

但是会返回以下错误:

Cannot determine length of [object Object]'

编辑2:

  • node版本:0.8.6(我也尝试过0.8.22和0.10.0)
  • aws-sdk:0.9.7-pre.8(今天安装)

完整的错误信息:

{ [Error: Cannot determine length of [object Object]]
  message: 'Cannot determine length of [object Object]',
  object:
  { _handle:
   { writeQueueSize: 0,
    owner: [Circular],
    onread: [Function: onread] },
 _pendingWriteReqs: 0,
 _flags: 0,
 _connectQueueSize: 0,
 destroyed: false,
 errorEmitted: false,
 bytesRead: 0,
 _bytesDispatched: 0,
 allowHalfOpen: undefined,
 writable: false,
 readable: true,
 _paused: false,
 _events: { close: [Function], error: [Function: handlerr] } },
name: 'Error' }
1个回答

13

你不需要自己读取流(在您的情况下,似乎由于var str =''将二进制转换为字符串,然后附加数据,而数据是一个二进制缓冲区等...).

尝试让putObject像这样传输流:

gm(request('http://www.some-domain.com/some-image.jpg'), "my-image.jpg")
  .resize("100^", "100^")
  .stream(function(err, stdout, stderr) {
      var data = {
        Bucket: "my-bucket",
        Key: "my-image.jpg",
        Body: stdout
        ContentType: mime.lookup("my-image.jpg")
      };
      s3.client.putObject(data, function(err, res) {
        console.log("done");
      });
    });
  });

查看这些发布说明以获取更多信息。

如果流式传输/管道不起作用,那么可能会使用类似于以下的方法,将所有内容加载到内存中,然后上传。在这种情况下,您的限制是4MB(我想是这样)。

    var buf = new Buffer('');
    stdout.on('data', function(data) {
       buf = Buffer.concat([buf, data]);
    });
    stdout.on('end', function(data) {
      var data = {
        Bucket: "my-bucket",
        Key: "my-image.jpg",
        Body: buf,
        ContentType: mime.lookup("my-image.jpg")
      };
      s3.client.putObject(data, function(err, res) {
        console.log("done");
      });
    });

这是我尝试的第一件事,因为stdout应该已经是一个流了,对吧?但是那行不通,在最后一个回调中的'err'提示说“无法确定[object Object]的长度”;-( - hereandnow78
你有堆栈跟踪吗?你正在使用最新版本的aws-SDK吗? - AndyD
不,这就是我得到的全部信息。我认为aws-sdk存在问题,我在他们的github页面上开了一个issue:https://github.com/aws/aws-sdk-js/issues/94 - hereandnow78
你的缓冲区示例有效(当你使用空字符串“new Buffer('')”实例化缓冲区时)。我会接受并点赞你的答案,因为它帮助解决了我的原始问题。当然,我更喜欢真正的流式解决方案,但我认为这是一个AWS-SDK问题。非常感谢! - hereandnow78
感谢。您也可以使用knox + knox-mpu(多部分上传)模块来进行流式传输,但我现在更喜欢官方SDK。 - AndyD

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