Javascript AWS SDK S3上传方法,Body流生成空文件

时间:2017-05-23 22:07:05

标签: node.js amazon-s3 upload stream

我尝试使用模块fs中的ReadableStream从 s3 中使用上传方法。

documentation表示可以在Body param使用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,只要我生成它。

2 个答案:

答案 0 :(得分:14)

使用NodeJS ReadableStreams是一个API接口问题。 只需注释与侦听事件'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会启动流动模式(收听更改发布商/ EventEmitter状态的事件?是的,非常容易出错...)。出于某种原因,S3需要暂停 ReadableStream。如果在rs.on('data'...) await s3.upload(...)之后将其放置rs.pause()。如果我们在rs.on('data'...)和befote await s3.upload(...)之后添加.so,那么它也有效。

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

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

答案 1 :(得分:1)

  1. 检查文件/home/osman/Downloads/input.txt是否确实存在且可由node.js进程访问
  2. 考虑使用putObject方法
  3. 示例:

    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)
    });