【问题标题】:stream response from nodejs request to s3从 nodejs 请求到 s3 的流式响应
【发布时间】:2015-06-17 21:38:16
【问题描述】:

如何使用 request 下载文件内容并使用 aws-sdk for node 将其直接流式传输到 s3?

下面的代码给了我Object #<Request> has no method 'read',这使得请求似乎没有返回可读流......

var req = require('request');
var s3 = new AWS.S3({params: {Bucket: myBucket, Key: s3Key}});
var imageStream = req.get(url)
    .on('response', function (response) {
      if (200 == response.statusCode) {
        //imageStream should be read()able by now right?
        s3.upload({Body: imageStream, ACL: "public-read", CacheControl: 5184000}, function (err, data) {  //2 months
          console.log(err,data);
        });
      }
    });
});

根据aws-sdk docs Body 需要是ReadableStream 对象。

我在这里做错了什么?

这可以使用s3-upload-stream 模块完成,但是我更愿意限制我的依赖项。

【问题讨论】:

  • req 在哪里/如何定义?
  • @mscdex 问题已更新以反映 req

标签: node.js amazon-s3 aws-sdk requestjs


【解决方案1】:

由于我在 request@2.60.0 和 aws-sdk@2.1.43 遇到了与 @JoshSantangelo(S3 上的零字节文件)相同的问题,因此让我使用 Node 自己的 http 模块添加替代解决方案(警告:来自真实项目的简化代码,未单独测试):

var http = require('http');

function copyToS3(url, key, callback) {
    http.get(url, function onResponse(res) {
        if (res.statusCode >= 300) {
            return callback(new Error('error ' + res.statusCode + ' retrieving ' + url));
        }
        s3.upload({Key: key, Body: res}, callback);
    })
    .on('error', function onError(err) {
        return callback(err);
    });
}

据我所知,问题在于request 不完全支持当前的Node Stream API,而aws-sdk 依赖于它。

参考资料:

【讨论】:

  • 这是唯一对我有用的解决方案。谢谢。
  • 这行得通——但我不得不使用 https 而不是 http
  • 一个简单的 https 开关: var http = require('http'); var https = 需要('https'); if (url.toString().indexOf("https") === 0){ http = https; }
【解决方案2】:

如果您手动侦听响应流,您想使用response 对象:

var req = require('request');
var s3 = new AWS.S3({params: {Bucket: myBucket, Key: s3Key}});
var imageStream = req.get(url)
    .on('response', function (response) {
      if (200 == response.statusCode) {
        s3.upload({Body: response, ACL: "public-read", CacheControl: 5184000}, function (err, data) {  //2 months
          console.log(err,data);
        });
      }
    });
});

【讨论】:

  • 谢谢!对于其他人来说,请求记录的获取流的方式有点误导github.com/request/request/issues/931
  • 我遇到了同样的问题——这个答案很有帮助,但 s3 上的文件最终为零字节。将相同的请求通过管道传输到磁盘会产生一个有效的文件。
  • @JoshSantangelo 如果你仍然有这个问题,也许看看我的替代解决方案。
  • @JoshSantangelo 可能为时已晚,但可能是您使用了错误的编码。如果您不提供编码,请求假定文本数据,例如图像数据将被损坏。使用 req.get({ url: url, encoding: null })。不过,零字节看起来很奇怪。
  • 知道如何指定文件存储的名称吗?
【解决方案3】:

Request 已被弃用,这里有一个利用 Axios 的解决方案

const AWS = require('aws-sdk');
const axios = require('axios');

const downloadAndUpload = async function(url, fileName) {
  const res = await axios({ url, method: 'GET', responseType: 'stream' });
  const s3 = new AWS.S3(); //Assumes AWS credentials in env vars or AWS config file
  const params = {
    Bucket: IMAGE_BUCKET, 
    Key: fileName,
    Body: res.data,
    ContentType: res.headers['content-type'],
  };
  return s3.upload(params).promise();
}

请注意,如果 AWS 凭证错误或丢失,当前版本的 AWS 开发工具包不会引发异常 - 承诺永远不会解决。

【讨论】:

  • 我正在尝试与此非常相似的东西,但这是在测试文件中运行的(开玩笑)。所以代码块包含在await expect(new Promise((resolve, reject) => { 中。我将您的代码封装在一个异步函数中,例如const resp = async (url) => {,然后调用resp。问题是我最终会超时。你有什么建议吗?
  • 我注意到,如果凭证丢失或不起作用,AWS sdk 不会抛出错误 - 它只是从不响应,所以可能先检查一下。
  • +1 这也是我的问题。我希望我在敲打我的头几天并尝试不同的方法来解决这个问题之前就知道这一点。谢谢@skoll
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-11
  • 1970-01-01
  • 1970-01-01
  • 2019-06-22
  • 1970-01-01
相关资源
最近更新 更多