[strapi]使用 S3 上传提供商的图像有时返回 CDN URL,有时返回 S3 签名 URL

2024-05-13 433 views
6
错误报告 所需的系统信息
  • Node.js 版本:
  • NPM版本:v18.16.0
  • 斯特拉皮版本:4.11.1
  • 数据库:Postgresql
  • 操作系统:MacOS
  • 你的项目是Javascript还是Typescript:Typescript
描述错误

图像 URL 和 API 存在奇怪的行为。我在 Cloudfront 上设置了 @strapi/provider-upload-aws-s3 (请参阅下面的配置),如果我查询上传及其各自的 URL,我会得到 Cloudfront URL,但如果我查询相关实体,在我的例子中为“产品”以及它们各自的图像和 URL,然后我得到带有签名的 S3 URL。我绝对不想向用户公开 S3 URL,而只想使用 Cloudfront。

我显示的图像适用于 Graphql API,但 REST API 也会发生同样的情况。我认为解决此问题的方法是分别查询图像和产品,然后自己加入数据,但似乎 Strapi 应该更好地处理这种情况。

查询:

图像

使用 Cloudfront URL 上传:

图像

具有 S3 URL 的产品:

图像

S3配置:

屏幕截图 2023-06-20 下午 6 43 38 图像 重现行为的步骤
  1. 使用像我这样的配置设置 S3 上传插件(主要取自文档)
  2. 上传一些图片,创建另一种与图片相关的内容类型
  3. 通过API查询图片的URL
  4. 查看相关图像如何使用 S3 URL
预期行为

我期望 Cloudfront URL 能够在任何地方一致地返回。

如果您需要更多信息来诊断,请告诉我,谢谢。

回答

9

您好,在 @strapi/provider-upload-aws-s3 设置中,您的 ACL 是否设置为私有?

7

我愿意,是的。

2

好吧,这可能与 uploadFiles 查询不签署文件有关,但我不建议在这里使用 ACL 设置为私有的 CDN。因为文件签名将返回您的存储桶的 URL,而不是您的 CDN。

https://github.com/strapi/strapi/blob/main/packages/providers/upload-aws-s3/src/index.ts#L76

您也应该在启动时看到此警告消息。

不过,您所展示的是一个必须解决的问题。我们将致力于解决这个问题,您可能会看到所有内容类型的 URL 都已签名。

8

抱歉,如果这看起来令人困惑,但我不需要/想要签名的 Cloudfront URL,部分原因是这会破坏浏览器缓存,就像当前签名的 S3 URL 发生的情况一样。也就是说,这些文件确实需要是私有的,并且不能直接从 S3 公开读取。当前的上传插件 + API 设置似乎有点混淆 S3 设置和 Cloudfront 设置之间的差异。

为了澄清一点,我遵循我所理解的公开托管图像的推荐设置。文件在 S3 中是私有的,ACL 被禁用,因此没有文件可以直接从 S3 公开读取。只有 Cloudfront 发行版可以通过存储桶策略从 S3 读取文件。然后,通过 CDN 的文件可公开访问,并且 URL 未签名,使其始终相同且浏览器缓存友好。

我不确定上传插件和 API 之间的确切区别在哪里,但是看看上传的作用以及数据库数据的样子,这似乎是正确的:

图片(1)

然后,在某些情况下,API 会决定不返回此 URL,而是计算签名的 S3 URL 并返回该 URL,但它不应该这样做,或者应该有一个选择退出的选项。

8

@Marc-Roig 你忘了添加状态。

2

^4.10.5我相信自从今天升级 Strapi(和这个插件)以来我遇到了同样的问题^4.11.2

我正在使用 REST API。当我查询单个条目(例如/api/entries/1)时,图像 url 使用baseUrl我设置的设置(我的 CDN url)正确返回。但是,当我查询索引页面(例如/api/entries)时,图像 url 全部不正确并返回直接 S3 url。对于多种集合类型,都会发生这种情况。单一端点始终返回正确的 url,而索引端点则不会。

此外,Strapi 管理员开始使用不正确的直接 S3 URL。我第一次注意到这一点是因为它们都无法在管理面板中加载。一旦我将xxx.s3.amazonaws.com域添加到我的contentSecurityPolicy配置中以允许它们再次开始工作。

有趣的是......将 Strapi 降级回我手动设置的版本package.json并没有直接解决问题。但是,对我的提交进行完全还原(这也还原了 package-lock.json 中的任何更改)!因此,可能是一些不直接在我的 package.json 中的相关依赖项导致了问题。

屏幕截图 2023-06-22 晚上 8 点 50 分 49 分
5

然后,在某些情况下,API 会决定不返回此 URL,而是计算签名的 S3 URL 并返回该 URL,但它不应该这样做,或者应该有一个选择退出的选项。

如果您的上传插件配置将 ACL 设置为私有,您就会出现这种行为。因此,如果您取消设置该属性或将其设置为“公共读取”,它应该修复该行为并始终返回 cloudfront url

3

在最近的版本中,我们改变了对 URL 进行签名的方式,以提供一些上下文:

使用 CDN 对 URL 进行签名是一项技术限制,只能通过创建自定义上传插件来解决。相反,如果您不需要签名 URL,则不应将 ACL 设置为私有。

我将在文档中添加一个部分来更好地解释这一点。

2
If your upload plugin configuration sets the ACL to be private, you will have that behaviour.
So if you unset the attribute or set it to 'public-read' it should fix the behaviour and always return the cloudfront url

我明白了,但这似乎不对。这是假设,因为我需要 S3 中的私有对象,所以我希望使用签名 URL 来访问它们,但情况可能并非如此。顺便说一句,我确实尝试过这种改变,并得到了这个:

图像

对我来说,在 S3 中启用 ACL 是不可能的,AWS 不推荐这样做,并且这被视为一种不好的做法。我认为这应该是两个不同的配置设置,当前的ACL一个仅设置 S3 对象的权限,另一个设置控制是否需要对公共 URL 进行签名。我猜想,如果未指定第二个设置,并且未指定 CDN,您可以假设 ACL=private 自动触发签名 URL 的当前行为,但否则,它只是假设太多。

7

你是完全正确的,你的建议似乎是一个非常好的解决方案。我将添加另一个参数来设置文件是否应该签名。我将在本周发布有关此问题的后续文章,并希望准备好公关? 。

5

太棒了,感谢您考虑这一切。如果我能提供任何帮助,请告诉我,也许可以进行测试。

7

你好!抱歉耽搁了,但我已经打开了一个 PR 来解决这个问题:) 如果你想测试它,我已经创建了一个实验版本:0.0.0-experimental.133ddc2de4e58dc1eb476fda8e0a67b0f1ee6e74

我们可能会在下周的 4.11.4 版本中发布这个版本?