1

我试图弄清楚如何通过我在 Node.js/Restify 中编写的 RESTful API 将数据上传到 Amazon S3 存储桶。我想我已经掌握了所有基本概念,但是当我连接到我的 POST 请求的主体时,事情就会出错。当我将回调函数设置为简单地将字符串传递给 S3 时,它工作得很好,并且文件在适当的 S3 存储桶中创建:

function postPoint(req, res, next) {

  var point = [
    { "x": "0.12" },
    { "y": "0.32" }
  ];

  var params = { Bucket: 'myBucket', Key: 'myKey', Body: JSON.stringify(point) };

  s3.client.putObject(params, function (perr, pres) {
    if (perr) {
        console.log("Error uploading data: ", perr);
    } else {
        console.log("Successfully uploaded data to myBucket/myKey");
    }
  });

  res.send(200);
  return next();
}

server.post('/point', postPoint);

显然,我最终需要从请求正文中流式传输/管道传输我的请求。我假设我需要做的就是简单地将参数的主体切换到请求流:

function postPoint(req, res, next) {

  var params = { Bucket: 'myBucket', Key: 'myKey', Body: req };

  s3.client.putObject(params, function (perr, pres) {
    if (perr) {
        console.log("Error uploading data: ", perr);
    } else {
        console.log("Successfully uploaded data to myBucket/myKey");
    }
  });

  res.send(200);
  return next();
}

但这最终导致显示以下日志消息:“上传数据时出错:[TypeError:路径必须是字符串]”,这几乎没有告诉我我需要做什么来修复错误。最终,我希望能够通过管道传输结果,因为发送的数据可能非常大(我不确定前面的示例是否导致正文存储在内存中),所以我认为这样的事情可能会奏效:

function postPoint(req, res, next) {

  var params = { Bucket: 'myBucket', Key: 'myKey', Body: req };

  req.pipe(s3.client.putObject(params));

  res.send(200);
  return next();
}

因为我在 GET 函数中做了类似的事情,效果很好:( s3.client.getObject(params).createReadStream().pipe(res);)。但这也没有用。

在这一点上我有点茫然,所以任何指导将不胜感激!

4

1 回答 1

3

所以,在 AWS 开发者论坛上发帖后,我终于找到了答案。事实证明,我的 S3 请求中缺少 Content-Length 标头。Loren@AWS总结得很好:

为了将任何对象上传到 S3,您需要提供 Content-Length。通常,SDK 可以从 Buffer 和 String 数据(或任何具有 .length 属性的对象)推断内容,并且我们对文件流进行特殊检测以获取文件长度。不幸的是,SDK 无法计算出任意流的长度,因此如果您传递 HTTP 流之类的内容,则需要自己手动提供内容长度。

建议的解决方案是简单地从 http.IncomingMessage 对象的标头传递内容长度:

var params = {
  Bucket: 'bucket', Key: 'key', Body: req,
  ContentLength: parseInt(req.headers['content-length'], 10)
};
s3.putObject(params, ...);

如果有人有兴趣阅读整个线程,您可以在此处访问。

于 2013-06-21T11:08:28.687 回答