如何在 Rails 环境中使用 Cache-Control: max-age Header 来控制 Varnish 和浏览器?
Posted
技术标签:
【中文标题】如何在 Rails 环境中使用 Cache-Control: max-age Header 来控制 Varnish 和浏览器?【英文标题】:Howto control Varnish and a Browser using Cache-Control: max-age Header in a Rails environment? 【发布时间】:2012-05-04 07:35:54 【问题描述】:最近我向 Rails 应用程序堆栈添加了一个 Varnish 实例。可以通过使用 Cache-Control Header 缓存某个资源来说服其默认配置中的清漆,如下所示:
Cache-Control: max-age=86400, public=true
我使用控制器中的 expires_in 语句实现了这一点:
def index
expires_in 24.hours, public: true
respond_with 'some content'
end
效果很好。我没想到的是,Cache-Control 标头也会影响浏览器。这导致了一个问题 - Varnish 和我的用户浏览器都缓存了某个资源。资源已从清漆中正确清除,但浏览器不会尝试再次请求它,除非达到 max-age。
所以我想知道我是否应该将“expires_in”与 Varnish 结合使用?我可以在 Varnish 前面过滤 nginx 或 Apache 实例中的 Cache-Control 标头,但这似乎很奇怪。
谁能赐教?
问候 费利克斯
【问题讨论】:
我遇到了同样的问题。您找到解决方案了吗? 【参考方案1】:这实际上是一个非常好的和有效的问题,也是一个非常常见的反向代理问题。
问题在于只有一个 Cache-Control 属性,它是为客户端浏览器(私有缓存)和/或代理服务器(共享缓存)设计的。如果您根本不希望 3rd 方代理缓存您的内容,并且希望您的 Varnish(或 Rails 后端)处理每个请求,您必须从 Varnish 发送适当的 Cache-Control 标头。
修改后端发送的Cache-Control标头在https://www.varnish-cache.org/trac/wiki/VCLExampleLongerCaching详细讨论
您可以从两个不同的角度来解决问题。如果你想在 Rails 后端定义 max-age,例如为不同的对象指定不同的 TTL,你可以使用上面链接中描述的方法。
另一种解决方案是根本不从后端发送 Cache-Control 标头,而是在 varnish vcl_fetch() 中为对象定义所需的 TTL。这是我们采取的方法。
我们在 Varnish 中有一个 600 秒的默认 TTL,并为在进行更改时明确清除的页面定义更长的 TTL。这是我们当前的 vcl_fetch() 定义:
sub vcl_fetch
if (req.http.Host ~ "(forum|discus)")
# Forum pages are purged explicitly, so cache them for 48h
set beresp.ttl = 48h;
if (req.url ~ "^/software/")
# Software pages are purged explicitly, so cache them for 48h
set beresp.ttl = 48h;
if (req.url ~ "^/search/forum_search_results" )
# We don't want forum search results to be cached for longer than 5 minutes
set beresp.ttl = 300s;
if(req.url == "/robots.txt")
# Robots.txt is updated rarely and should be cached for 4 days
# Purge manually as required
set beresp.ttl = 96h;
if(beresp.status == 404)
# Cache 404 responses for 15 seconds
set beresp.http.Cache-Control = "max-age=15";
set beresp.ttl = 15s;
set beresp.grace = 15s;
在我们的例子中,我们根本不从 Web 后端服务器发送 Cache-Control 标头。
【讨论】:
感谢您的详细回答。我们通过简单地将 Cache-Control 标头更改为: Cache-Control: max-age=0 s-maxage=86400, public=true 解决了这个问题,因此浏览器不会缓存资源,而是像 Varnish 那样共享缓存。有错吗? 您也可以使用 s-maxage。但是,如果您的用户使用透明代理(一些 ISP 仍在使用它们),他们也会看到缓存版本长达 24 小时。如果需要,可以使用 s-maxage。如果没有,那么您应该从 VCL 中的响应中删除缓存控制标头。我将编辑我的答案以提及 s-maxage。 感谢您提供相关信息。我们一定会根据您的解决方案对此进行重构和更改。 确实如此。 s-maxage 绝对是最简单的方法。确保从 vcl_deliver 中的 Cache-Control 标头中删除 s-maxage 以防止下游缓存使用它。您可以使用 regsub 对其进行过滤。如果您在后端同时设置 s-maxage 和 max-age,您将获得一个非常灵活的系统,允许您为 Varnish 和客户端设置不同的 TTL,同时避免在 VCL 代码中硬编码 TTL。以上是关于如何在 Rails 环境中使用 Cache-Control: max-age Header 来控制 Varnish 和浏览器?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Rails 环境中使用 Cache-Control: max-age Header 来控制 Varnish 和浏览器?