我有一个运行Hapi的Nodejs服务器。
服务器的一项工作是将文件发送到服务者API(该API仅在我发送缓冲区时接受流,并且它返回错误),应用户询问
所有文件都存储在s3中。 如果我使用promise()下载它们, 我进入身体缓冲区。 如果我使用的是createReadStream(),则可以通过。
我的问题是,当我尝试将缓冲区转换为流并发送给API拒绝它时,和使用createReadStream()结果时一样, 但是当我使用FS保存文件,然后使用FS读取API时,接受该流及其工作。
所以我需要帮助,如何在不保存和读取文件的情况下创建相同的结果。
编辑: 这是我的代码,我知道这是错误的方法,但是它可以工作,但我需要一种更好的方法来工作
static async downloadFile(Bucket, Key) {
const result = await s3Client
.getObject({
Bucket,
Key
})
.promise();
fs.writeFileSync(`${Path.basename(Key)}`,result.Body);
const file = await fs.createReadStream(`${Path.basename(Key)}`);
return file;
}
答案 0 :(得分:0)
如果我对它的理解正确,那么您希望从s3存储桶中获取该对象,并将其作为流传输到HTTP响应。
与其获取缓冲区中的数据,而不是弄清楚将其转换为流的方式可能会很复杂并且有其局限性,如果您真的想利用流的力量,那么不要尝试将其转换为缓冲区并将整个对象加载到内存中,您可以通过在请求上调用createReadStream方法来创建一个将返回的数据直接流式传输到Node.js Stream对象的请求。
调用createReadStream返回由请求管理的原始HTTP流。然后可以将原始数据流通过管道传递到任何Node.js Stream对象中。
此技术对于在有效载荷中返回原始数据的服务调用很有用,例如,在Amazon S3服务对象上调用getObject将数据直接流式传输到文件中,如本示例所示。
//I Imagine you have something similar.
server.get ('/image', (req, res) => {
let s3 = new AWS.S3({apiVersion: '2006-03-01'});
let params = {Bucket: 'myBucket', Key: 'myImageFile.jpg'};
let readStream= s3.getObject(params).createReadStream();
// When the stream is done being read, end the response
readStream.on('close', () => {
res.end()
})
readStream.pipe(res);
});
使用createReadStream从请求中流式处理数据时,仅返回原始HTTP数据。 SDK不会对数据进行后处理,可以直接返回原始HTTP数据。
注意: 由于Node.js无法回退大多数流,因此,如果请求最初成功,则将在其余响应中禁用重试逻辑。如果套接字发生故障,则在流传输期间,SDK不会尝试重试或向流发送更多数据。您的应用程序逻辑需要识别并处理此类流失败。
修改: 在对原始问题进行编辑之后,我可以看到s3发送了一个PassThrough流对象,该对象与Nodejs中的FileStream不同。因此,要解决此问题,请使用内存(如果您的文件不是很大,或者您有足够的内存)。
使用软件包memfs
,它将替换您应用中的本机fs
https://www.npmjs.com/package/memfs
通过npm install memfs
安装软件包,并要求如下:
const {fs} = require('memfs');
您的代码将如下所示
static async downloadFile(Bucket, Key) {
const result = await s3
.getObject({
Bucket,
Key
})
.promise();
fs.writeFileSync(`/${Key}`,result.Body);
const file = await fs.createReadStream(`/${Key}`);
return file;
}
请注意,我对您的功能所做的唯一更改是将路径${Path.basename(Key)}
更改为/${Key}
,因为现在您无需知道原始文件系统的路径将文件存储在内存中。我已经测试过并且该解决方案有效