从AWS S3到Node.js服务器的文件检索,然后传输至React客户端。

3

我需要使用 Node.js 和 Express.js 从服务器上检索单个文件。为此,我安装了 aws-sdk@aws-sdk/client-s3。我能够成功使用这个简单的端点获取文件:

const app = express(),
      { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3'),
      s3 = new S3Client({ region: process.env.AWS_REGION });

app.get('/file/:filePath', async (req,res) => {
  const path_to_file = req.params.filePath;

  try {
    const data = await s3.send(new GetObjectCommand({ Bucket: process.env.AWS_BUCKET, Key: path_to_file }));
    console.log("Success", data);
  } catch (err) {
    console.log("Error", err);
  }
});

...但我不知道如何正确地将data返回到React.js前端,以便文件可以进一步下载。我尝试查阅文档,但对我来说太乱了,我甚至不知道函数返回什么。.toString()方法没有帮助,因为它只是简单地返回`"[object Object]"`而已。

在React上,我正在使用一个名为file-saver的库,它使用blob并提供由用户定义的文件名进行下载。

Node v15.8.0,React v16.4.0,@aws-sdk/client-s3 v3.9.0,file-saver v2.0.5

感谢您的提示和建议!任何帮助都将不胜感激。


你应该考虑直接向客户端发送预签名的URL,让客户端直接从S3下载文件。 - jarmod
这不是客户要求的内容。所要求的是创建一个代理文件,以便可见的URL来自他们的服务器,而不是S3。 - Rusurano
好的,这是一个选项,你可以将其隐藏在重定向后面,例如客户端请求/api/getfile/xyz.jpg,然后你响应一个302重定向到S3预签名URL。除此之外,使用Express res.sendFile()有什么问题吗?使用AWS SDK将文件下载到Web服务器,然后从下载位置提供服务。这对你不起作用吗? - jarmod
2个回答

2
一般情况下,从S3返回的数据是作为缓冲区返回的。文件内容是响应中Body参数的一部分。您可能正在对根对象进行toString操作。
您需要在body参数上使用.toString()将其转换为字符串。
以下是一些可能适用于您的用例的示例代码。
// Note: I am not using a different style of import
const AWS = require("aws-sdk")
const s3 = new AWS.S3()

const Bucket = "my-bucket"

async getObject(key){
 const data = await s3.getObject({ Bucket, key}).promise()
 if (data.Body) {return data.Body.toString("utf-8") } else { return undefined}
}


为了在express中返回这个,你可以在你的路由中添加这个,并在你获得最终数据后将其传回。
res.end(data));

在React中使用它应该与从任何其他REST API获取值相同。

1
我使用了 Ravi 的答案,但导致在前端无法显示图像对象。
这个可以正常工作:
  const data = await s3.send(new GetObjectCommand({ Bucket: process.env.AWS_BUCKET, Key: path_to_file }));
  data.Body.pipe(res);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接