NodeJS:使用流将图像文件上传到S3存储桶
NodeJS:使用流将图像文件上传到S3存储桶
我目前正在使用一个叫做s3-upload-stream的node.js插件,将非常大的文件流式传输到Amazon S3。它使用了多部分API,大部分情况下运行得很好。\n然而,这个模块已经显得有些过时了,我已经不得不对其进行修改(作者也已经将其弃用)。今天我遇到了另一个与Amazon相关的问题,我真的很想采纳作者的建议,开始使用官方的aws-sdk来完成我的上传操作。\n但是。\n官方的SDK似乎不支持对s3.upload()
进行流式传输。s3.upload的特性是必须将可读流作为参数传递给S3构造函数。\n我大约有120多个用户代码模块进行各种文件处理,它们对最终输出的目的地是无知的。引擎会给它们一个可传输的可写输出流,它们会将数据传输到这个流中。我不能给它们一个AWS.S3
对象,并要求它们调用upload()
方法,而不对所有模块添加代码。我之所以使用s3-upload-stream
是因为它支持流式传输。\n有办法让aws-sdk的s3.upload()
支持流式传输吗?
问题的原因是使用流将图像文件上传到S3存储桶时出现了错误。解决方法是返回可写流和Promise,以便在上传完成时获取响应数据。
首先,我们需要引入依赖库:
const AWS = require('aws-sdk'); const stream = require('stream');
然后,我们定义一个名为`uploadStream`的函数,该函数接受一个包含存储桶和键的对象作为参数。函数内部创建了一个S3实例和一个可传递的流对象,并返回一个包含可写流和Promise的对象:
const uploadStream = ({ Bucket, Key }) => { const s3 = new AWS.S3(); const pass = new stream.PassThrough(); return { writeStream: pass, promise: s3.upload({ Bucket, Key, Body: pass }).promise(), }; }
接下来,我们可以使用这个函数来上传文件。首先创建一个读取流和一个写入流,然后通过管道将读取流的内容写入到写入流中:
const { writeStream, promise } = uploadStream({Bucket: 'yourbucket', Key: 'yourfile.mp4'}); const readStream = fs.createReadStream('/path/to/yourfile.mp4'); const pipeline = readStream.pipe(writeStream);
上传完成后,我们可以通过检查Promise来处理结果:
promise.then(() => { console.log('上传成功'); }).catch((err) => { console.log('上传失败', err.message); });
或者使用async/await语法:
try { await promise; console.log('上传成功'); } catch (error) { console.log('上传失败', error.message); }
另外,由于`stream.pipe()`返回的是可写流,我们还可以使用它的事件来处理上传结果:
pipeline.on('close', () => { console.log('上传成功'); }); pipeline.on('error', (err) => { console.log('上传失败', err.message) });
以上是解决使用流将图像文件上传到S3存储桶的问题的方法。如果你遇到了类似的错误,可以参考这个解决方案。
问题的出现原因:用户想要使用Node.js将图像文件上传到S3存储桶,但是上传后的文件大小为0字节,无法正确上传文件。
解决方法:将S3的upload()函数使用node.js的stream.PassThrough()流进行封装,然后将数据流通过pipe()方法传递给S3进行上传。
代码示例:
inputStream .pipe(uploadFromStream(s3)); function uploadFromStream(s3) { var pass = new stream.PassThrough(); var params = {Bucket: BUCKET, Key: KEY, Body: pass}; s3.upload(params, function(err, data) { console.log(err, data); }); return pass; }
根据用户的反馈,该方法能够解决上传0字节文件的问题。其中stream.PassThrough()流的作用是接受写入的字节并将其输出。这样可以返回一个可写流供aws-sdk在写入时读取。同时,需要将s3.upload()方法的返回对象也返回,以确保上传完成。
用户进一步提到,如果将content-type更改为text/plain,则上传正常。还有其他用户表示,这种方法与直接将可读流传递给Body参数并没有本质区别,因为AWS SDK仍会调用PassThrough流的read()方法。
最后,用户还询问了代码中的s3和stream参数的来源,这些参数需要用户自行传入。
通过整理上述内容,我们可以得出以下文章:
NodeJS:使用流将图像文件上传到S3存储桶
在Node.js中,有时我们需要将文件上传到S3存储桶。然而,有些用户在使用流进行上传时遇到了问题,上传后的文件大小为0字节,无法正确上传文件。下面是一个解决上传问题的方法:
首先,我们需要使用stream.PassThrough()流对S3的upload()函数进行封装,代码示例如下:
inputStream .pipe(uploadFromStream(s3)); function uploadFromStream(s3) { var pass = new stream.PassThrough(); var params = {Bucket: BUCKET, Key: KEY, Body: pass}; s3.upload(params, function(err, data) { console.log(err, data); }); return pass; }
通过将数据流通过pipe()方法传递给S3进行上传,可以解决上传0字节文件的问题。stream.PassThrough()流的作用是接受写入的字节并将其输出,以便返回一个可写流供aws-sdk在写入时读取。同时,需要将s3.upload()方法的返回对象也返回,以确保上传完成。
有些用户提到,将content-type更改为text/plain后,上传就正常了。还有用户对上述方法提出了疑问,认为其与直接将可读流传递给Body参数没有本质区别,因为AWS SDK仍会调用PassThrough流的read()方法。
最后,需要注意的是,代码中的s3和stream参数需要用户自行传入。
通过以上方法,我们就可以成功使用Node.js将图像文件上传到S3存储桶了。