将存储在 S3 存储桶中的文件直接下载到 React 客户端,而不是通过 Node.js 服务器

Download file stored in S3 bucket directly to React client, instead of passing through Node.js server

this one from heroku这样的文章表明可以在一个人的节点服务器上签署一个请求并上传大文件直接从客户端到S3,但我还没有能够为 直接从 S3 下载 大文件到客户端找到类似的解决方案。

有关我在下面尝试执行的操作的更多信息:


我正在使用托管在 Heroku 上的 Node js 服务器构建 React 网络应用程序。用户创建和编辑音频文件,然后存储在 S3 存储桶中。

在接下来的会话中,音频必须再次从 S3 存储桶加载到用户的浏览器中。为此,Web 应用程序向节点 js 服务器发送请求,然后检索文件并将其发送到具有以下端点的客户端:

// LOAD AUDIO
router.get("/getaudio/:userEmail/:projectId/:sectionId", async (req, res) => {    

    //create key from user/project/section IDs
    const userEmail = req.params.userEmail;
    const projectId = req.params.projectId;
    const sectionId = req.params.sectionId;
    
    const key = `${userEmail}/${projectId}/${sectionId}.webm`;

    const params = {
        Key: key,
        Bucket: s3BucketName
    }

    s3.getObject(params, function (error, data) {
        if (error) {
            console.error(error);
        }
        res.send(data);
    });
    
});

这里的问题是音频文件可能非常大(长达 1.5 小时)。将这些文件加载​​到 Node js 服务器,然后 然后 将它们发送到客户端感觉效率非常低,并且可能导致我的 Heroku dyno 上不必要的负载,以及用户非常长的等待时间。

但是,我不想在我的客户端中直接使用 AWS SDK(完全切断服务器),因为有人告诉我这是不好的做法,并且会暴露您的环境变量。

有没有办法将大文件从我的 s3 存储桶中安全可靠地直接下载到 React 客户端?

您可以在您的 node.js 服务器上生成一个 presigned URL 来授予对 s3 对象的访问权限,将其 URL 发送到您的 React 应用程序并直接从 React 下载文件应用

请务必注意,预签名 URL 默认情况下会在 15 分钟后过期。因此,如果您需要增加过期时间,您可以通过传递 Expires 参数来指定您的 URL 保持多长时间(以秒为单位)有效。

您的 node.js 处理程序可能如下所示:

router.get("/getaudio/:userEmail/:projectId/:sectionId", async (req, res, next) => {

    //create key from user/project/section IDs
    const userEmail = req.params.userEmail;
    const projectId = req.params.projectId;
    const sectionId = req.params.sectionId;

    const key = `${userEmail}/${projectId}/${sectionId}.webm`;

    const params = {
        Key: key,
        Bucket: s3BucketName
    }

    s3.getSignedUrl('getObject', params, function (err, url) {
        if (err) {
            console.error(err)
            next(err);
        } else {
            res.json({ url })
        }
    })

});