【问题标题】:Javascript AWS SDK S3 upload method with Body stream generating empty fileJavascript AWS SDK S3上传方法与正文流生成空文件
【发布时间】:2017-10-24 01:20:54
【问题描述】:

我正在尝试使用来自 s3 的方法 upload,使用模块 fs 中的 ReadableStream。

documentation 表示可以在 Bodyparam 处使用 ReadableStream:

Body — (Buffer, Typed Array, Blob, String, ReadableStream) 对象数据。

另外上传方法描述为:

上传任意大小的缓冲区、blob 或流,如果有效负载足够大,则使用部分的智能并发处理。

另外,在这里:Upload pdf generated to AWS S3 using nodejs aws sdk @shivendra 说他可以使用 ReadableStream 并且它可以工作。

这是我的代码:

const fs = require('fs')
const S3 = require('aws-sdk/clients/s3')

const s3 = new S3()

const send = async () => {
  const rs = fs.createReadStream('/home/osman/Downloads/input.txt')
  rs.on('open', () => {
    console.log('OPEN')
  })
  rs.on('end', () => {
    console.log('END')
  })
  rs.on('close', () => {
    console.log('CLOSE')
  })
  rs.on('data', (chunk) => {
    console.log('DATA: ', chunk)
  })

  console.log('START UPLOAD')

  const response = await s3.upload({
    Bucket: 'test-bucket',
    Key: 'output.txt',
    Body: rs,
  }).promise()

  console.log('response:')
  console.log(response)
}

send().catch(err => { console.log(err) })

它得到这个输出:

START UPLOAD
OPEN
DATA: <Buffer 73 6f 6d 65 74 68 69 6e 67>
END
CLOSE
response:
{ ETag: '"d41d8cd98f00b204e9800998ecf8427e"',
  Location: 'https://test-bucket.s3.amazonaws.com/output.txt',
  key: 'output.txt',
  Key: 'output.txt',
  Bucket: 'test-bucket' }

问题是我在 S3 (output.txt) 生成的文件有 0 字节。

有人知道我做错了什么吗?

如果我在 Body 上传递一个缓冲区,它就可以工作。

Body: Buffer.alloc(8 * 1024 * 1024, 'something'), 

但这不是我想做的。只要我生成它,我想使用流来生成文件并将流通过管道传输到 S3。

【问题讨论】:

    标签: node.js amazon-s3 upload stream


    【解决方案1】:

    这是使用 NodeJS ReadableStreams 的 API 接口问题。 将listen事件相关代码注释'data'即可,问题解决。

    const fs = require('fs')
    const S3 = require('aws-sdk/clients/s3')
    
    const s3 = new S3()
    
    const send = async () => {
      const rs = fs.createReadStream('/home/osman/Downloads/input.txt')
      rs.on('open', () => {
        console.log('OPEN')
      })
      rs.on('end', () => {
        console.log('END')
      })
      rs.on('close', () => {
        console.log('CLOSE')
      })
      // rs.on('data', (chunk) => {
      //   console.log('DATA: ', chunk)
      // })
    
      console.log('START UPLOAD')
    
      const response = await s3.upload({
        Bucket: 'test-bucket',
        Key: 'output.txt',
        Body: rs,
      }).promise()
    
      console.log('response:')
      console.log(response)
    }
    
    send().catch(err => { console.log(err) })
    

    虽然这是一个奇怪的 API,但当我们监听 'data' 事件时,ReadableStream 会启动 flowing 模式(监听事件更改发布者/EventEmitter 状态?是的,非常容易出错。 ..)。出于某种原因,S3 需要暂停 ReadableStream。如果将rs.on('data'...) 放在await s3.upload(...) 之后,它会起作用。如果我们将rs.pause() 放在rs.on('data'...) 之后并放在await s3.upload(...) 之前,它也可以工作。

    现在,发生了什么?我还不知道...

    但是问题已经解决了,即使没有完全解释。

    【讨论】:

      【解决方案2】:
      1. 检查文件/home/osman/Downloads/input.txt 是否确实存在并且可以被node.js 进程访问
      2. 考虑使用putObject方法

      例子:

      const fs = require('fs');
      const S3 = require('aws-sdk/clients/s3');
      
      const s3 = new S3();
      
      s3.putObject({
        Bucket: 'test-bucket',
        Key: 'output.txt',
        Body: fs.createReadStream('/home/osman/Downloads/input.txt'),
      }, (err, response) => {
        if (err) {
          throw err;
        }
        console.log('response:')
        console.log(response)
      });
      

      不确定这将如何与async .. await 一起使用,最好先上传到 AWS:S3,然后更改流程。


      更新: 尝试直接通过ManagedUpload实现上传

      const fs = require('fs');
      const S3 = require('aws-sdk/clients/s3');
      
      const s3 = new S3();
      
      const upload = new S3.ManagedUpload({
        service: s3,
        params: {
          Bucket: 'test-bucket',
          Key: 'output.txt',
          Body: fs.createReadStream('/home/osman/Downloads/input.txt')
        }
      });
      
      upload.send((err, response) => {
        if (err) {
          throw err;
        }
        console.log('response:')
        console.log(response)
      });
      

      【讨论】:

      • 文件存在且可访问。 DATA: &lt;Buffer 73 6f 6d 65 74 68 69 6e 67&gt; 行表示已阅读。 putObject 在一次 HTTP 请求上发送数据,它不会将其流式传输到 S3。 async .. await 在这里不是问题。谢谢!
      • @osmanpontes 不会就此争论,你是对的。您是否尝试过我建议将 putObject 更改为 upload 方法的代码?
      • @osmanpontes 无论如何,我建议尝试putObject 进行测试
      • 我试过了,它按预期工作。 ;]。你有更多的见解吗?
      • .upload() 方法最初是为浏览器创建的。这可能是行为不端的原因,要么它应该在 node.js 上工作——我们总是使用.putObject() 方法。它只有一项建议 - 最大文件大小为 5GB。而且我还没有在 SDK 源代码中找到作为单个 HTTP 请求发送的文件的证据,looks like .putObject() uses .upload() 作为底层代码。我建议看看source code
      猜你喜欢
      • 2020-08-11
      • 2019-01-12
      • 1970-01-01
      • 2018-01-21
      • 2018-02-25
      • 2014-05-27
      • 1970-01-01
      • 2012-12-31
      • 2021-07-17
      相关资源
      最近更新 更多