将S3与Active Storage结合使用时,“请求已过期”

时间:2018-07-24 15:31:20

标签: ruby-on-rails amazon-s3 ruby-on-rails-5 rails-activestorage

我第一次使用ActiveStorage。 在开发过程中一切正常,但在生产中(Heroku),我的图像无故消失了。

他们第一次显示正常,但现在没有图像显示。在控制台中,我可以看到此错误:

GET https://XXX.s3.amazonaws.com/variants/Q7MZrLyoKKmQFFwMMw9tQhPW/XXX 403 (Forbidden)

如果我尝试直接访问该URL,则会得到XML

<Error>
  <Code>AccessDenied</Code>
  <Message>Request has expired</Message>
  <X-Amz-Expires>300</X-Amz-Expires>
  <Expires>2018-07-24T13:48:25Z</Expires>
  <ServerTime>2018-07-24T15:25:37Z</ServerTime>
  <RequestId>291D41FAC6708334</RequestId>      
  <HostId>lEVGuwA6Hvlm/i40PeXaje9SEBYks9+uk6DvBs=</HostId>
</Error>

这就是我的看法

<div class="cover" style="background-image: url('<%= rails_representation_path(experience.thumbnail) %>')"></div>

这就是我模型中的东西

def thumbnail
  self.cover.variant(resize: "300x300").processed
end

用简单的话来说,我不希望图像过期但要一直存在。

谢谢

2 个答案:

答案 0 :(得分:5)

ActiveStorage不支持未过期的链接。它使用到期链接(私有),并仅支持在服务上以私有形式上传文件。

这对我来说也是一个问题,仅对S3做2个补丁(警告),one simple ~30lines覆盖了ActiveStorage,使其仅适用于未到期的(公共)链接,并且another that add an acl option to has_one_attached and has_many_attached methods

希望有帮助。

答案 1 :(得分:0)

您的问题并没有这么说,但是通常将带有CDN的AWS CloudFront等CDN与Rails应用程序结合使用。特别是在Heroku上,您可能想节省计算能力。

在这种情况下会发生什么。您照常渲染页面,并且所有图像都是从资产宿主CDN请求的,因为这是配置成集成页面的方式。它的设置可以从原始位置(也就是您的应用程序)中获取缓存中找不到的所有内容。

首先所有图像请求都通过。 ActiveStorage控制器为它们创建签名的URL,CDN继续传递它们,但也缓存它们。

现在是问题所在。默认情况下,签名的URL会在5分钟后过期,但是CDN缓存通常会更长。这是因为通常您使用摘要资产,这意味着它们不会在任何更改时按时间而是按名称失效。

解决方案很简单。 增加已签名URL的有效期,使其长于缓存的TTL 。现在,缓存会在其失效之前删除缓存的签名URL。

使用5.2中的ActiveStorage::Service.url_expires_in或直接在初始化程序see this answerRails.application.config.active_storage.service_urls_expire_in中设置URL到期。

要在CloudFront中设置缓存TTL:打开AWS控制台,选择分发,打开“行为”选项卡,向下滚动到以下字段:

the cloudfront ttl fields

然后有选择地发出无效信息,以强制重新缓存所有内容。

请记住,存在安全权衡。如果图像内容是私有的,则它们很可能不属于CDN,并且也不应该具有持久的临时URL。在这种情况下,请选择一个完全免除CDN附件的解决方案。您的应用程序将不得不承担在呈现相关页面之外对所有附加资产的URL进行签名的额外负担。

还要记住,这不一定是一个好的解决方案,而是更多的解决方法。使用上述设置,您将缓存重定向,而较重的请求将直接进入您的存储桶。 CDN的通常情况是大型媒体,而不是轻量级重定向。您确实可以减轻应用程序处理大量请求的负担。应该考虑多少是有效的优化。