即使有缓存控制: max-age=0, no-store,仍然从cloudfront刷新RefreshHit。

4

Cloudfront(云前置)针对一个不应该被缓存的请求进行了RefreshHit(刷新命中)。

enter image description here

它不应该被缓存,因为:

  1. 它有cache-control: max-age=0, no-store
  2. 最小TTL为0;以及
  3. 我创建了多个无效化(在/*上),因此缓存的资源不是来自历史部署

enter image description here

您有什么想法为什么会出现RefreshHits?

我还试过将Cache-Control修改为cache-control no-store, stale-if-error=0,在/*上创建新的无效化,并且这次在Firefox中看到了缓存命中:

enter image description here


那个页面建议启用“使用源缓存标头”,这听起来正是我们需要的,但是该设置似乎只在我们在行为上使用他们的“传统缓存设置”选项时才可用,而我们正在使用新的“缓存策略和源请求策略(推荐)”选项。 - Garrett
不行,因为我需要它缓存来自我的源的某些请求,但不是所有请求,所以我真的需要它基于源提供的“Cache-Control”指令进行缓存。 (用例并不那么相关,但与我们整个站点从jQuery迁移到Next.js有关) - Garrett
是的,这是一个有点奇怪的用例。我们目前正在逐页将网站从不可缓存的后端渲染的jinja2 / jQuery转换为可缓存的客户端渲染的React / Next.js。如果我们能够控制所有约100个页面的行为,使得当一个页面过渡到Next.js时,它会自动开始被缓存,那就太好了。只有在过渡期间才有这种用例。 - Garrett
3个回答

7
在与支持人员进行了广泛的交谈后,他们解释了情况。
所以,如果您设置no-store和最小TTL为0,则CloudFront确实不会存储您的资源。但是,如果您的源需要很长时间才能响应请求(因此很可能是重载),而CloudFront在等待响应的同时收到另一个相同的请求(相对于缓存键是相同的),那么它将发送一个响应给两个请求。这是为了减轻服务器的负荷。(请参见 文档)
支持人员称之为“collapse hits”,但我没有在文档中看到这个术语。
因此,似乎您无法使用单个行为来提供必须针对每个请求具有唯一响应的某些页面以及缓存其他页面。支持说:
“我刚刚确认了,对于最小TTL为0且cache-control: no-store的情况,我们无法禁用collapse hit。如果您确实需要完全禁用cloudfront缓存,可以使用缓存策略CachingDisabled”
我们将为我们需要缓存的每个路径前缀创建一个行为。对于我们的用例(从不可缓存的后端呈现的jinja2 / jQuery逐个转换为可缓存的客户端呈现React / Next.js),似乎没有更好的方法。

1
这是一个好消息(关于负载下的行为)。至于缓存控制,我认为您想在源上设置缓存控制为max-age=0,must-revalidate,public,并确保您还可以发送回ETag。 - Cory Silva
Garrett感谢你强调了“collapse hits”概念。@Cory,我已经测试了你的建议:添加max-age=0、must-revalidate、public甚至private指令都没有起作用,也就是说,第二次调用返回了来自第一次请求的缓存响应。 - Mercury

0

另一个技巧,可以避免缓存并仍然使用默认的CloudFront行为,是:有一个虚拟未使用的查询参数,其值等于每个请求的唯一值。

Python示例:

import requests
import uuid
requests.get(f'http://my-test-server-x.com/my/path?nochace={uuid.uuid4()}')
requests.get(f'http://my-test-server-x.com/my/path?nochace={uuid.uuid4()}')

请注意,两个调用都将到达目的地,并且不会从缓存中获取响应,因为uuid.uuid4()始终会生成唯一值。
这样做是有效的,因为默认情况下(如果未在“行为”部分中另有定义),查询参数是缓存键的一部分。
请注意:这样做将避免使用缓存,因此您的后端可能会负载过重。

0

对于 OP 的项目来说,可能已经太晚了,但我个人会使用一个简单的起点-响应 Lambda@Edge 函数和一个单一的缓存行为(/* 和缓存策略)来处理这个问题。您可以在起点-响应函数中编写所有的过滤/缓存逻辑。这样,您只需要在一个地方管理一个函数代码位,而不是一堆单独的缓存行为(以及可能是一堆缓存策略)。

例如,一个起点-响应函数,它查找来自您起点的缓存控制响应头。如果存在,则将其传回客户端。但是,如果不存在(或者您想用其他内容覆盖它),那么您可以在此处创建响应头。边缘不关心缓存控制头是来自您的起点还是来自起点-响应 Lambda。对于边缘来说,它都是一样的。


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