Javascript AWS SDK S3上传方法与正文流生成空文件
Posted
技术标签:
【中文标题】Javascript AWS SDK S3上传方法与正文流生成空文件【英文标题】:Javascript AWS SDK S3 upload method with Body stream generating empty file 【发布时间】:2017-10-24 01:20:54 【问题描述】:我正在尝试使用来自 s3 的方法 upload,使用模块 fs
中的 ReadableStream。
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。
【问题讨论】:
【参考方案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】:-
检查文件
/home/osman/Downloads/input.txt
是否确实存在并且可以被node.js 进程访问
考虑使用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: <Buffer 73 6f 6d 65 74 68 69 6e 67>
行表示已阅读。 putObject
在一次 HTTP 请求上发送数据,它不会将其流式传输到 S3。 async .. await
在这里不是问题。谢谢!
@osmanpontes 不会就此争论,你是对的。您是否尝试过我建议将 putObject
更改为 upload
方法的代码?
@osmanpontes 无论如何,我建议尝试putObject
进行测试
我试过了,它按预期工作。 ;]。你有更多的见解吗?
.upload()
方法最初是为浏览器创建的。这可能是行为不端的原因,要么它应该在 node.js 上工作——我们总是使用.putObject()
方法。它只有一项建议 - 最大文件大小为 5GB。而且我还没有在 SDK 源代码中找到作为单个 HTTP 请求发送的文件的证据,looks like .putObject()
uses .upload()
作为底层代码。我建议看看source code以上是关于Javascript AWS SDK S3上传方法与正文流生成空文件的主要内容,如果未能解决你的问题,请参考以下文章
Javascript || AWS S3 SDK &croppie 文件上传错误
AWS S3 SDK:中止正在进行的 putObject 上传
通过使用 AWS-SDK PHP 生成的预签名帖子拒绝 AWS S3 上传访问