Ruby-on-rails 如何在 Rails 环境中使用 Cache-Control: max-age Header 控制 Varnish 和浏览器?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10284813/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Howto control Varnish and a Browser using Cache-Control: max-age Header in a Rails environment?
提问by GeorgieF
Recently I added a Varnish instance to a Rails application stack. Varnish in it's default configuration can be convinced from caching a certain resource using the Cache-Control Header like so:
最近我向 Rails 应用程序堆栈添加了一个 Varnish 实例。可以通过使用 Cache-Control Header 缓存某个资源来说服默认配置中的 Varnish,如下所示:
Cache-Control: max-age=86400, public=true
I achieved that one using the expires_in statement in my controllers:
我在控制器中使用 expires_in 语句实现了这一目标:
def index
expires_in 24.hours, public: true
respond_with 'some content'
end
That worked well. What I did not expect is, that the Cache-Control header ALSO affects the browser. That leads to the problem that both - Varnish and my users browser cache a certain resource. The resource is purged from varnish correctly, but the browser does not attempts to request it again unless max-age is reached.
那效果很好。我没想到的是,Cache-Control 标头也会影响浏览器。这会导致问题 - Varnish 和我的用户浏览器都缓存了某个资源。资源已从 varnish 正确清除,但除非达到 max-age,否则浏览器不会尝试再次请求它。
So I wonder wether I should use 'expires_in' in combination with Varnish at all? I could filter the Cache-Control header in a Nginx or Apache instance in front of Varnish, but that seems odd.
所以我想知道我是否应该将 'expires_in' 与 Varnish 结合使用?我可以在 Varnish 前面过滤 Nginx 或 Apache 实例中的 Cache-Control 标头,但这似乎很奇怪。
Can anyone enlighten me?
任何人都可以启发我吗?
Regards Felix
问候菲利克斯
采纳答案by Ketola
That is actually a very good and valid question, and a very common one with reverse proxies.
这实际上是一个非常好的和有效的问题,并且是一个非常常见的反向代理问题。
The problem is that there's only one Cache-Control property and it is intended for the client browser (private cache) and/or a proxy server (shared cache). If you don't want 3rd party proxies to cache your content at all, and want every request to be served by your Varnish (or by your Rails backend), you must send appropriate Cache-Control header from Varnish.
问题是只有一个 Cache-Control 属性,它用于客户端浏览器(私有缓存)和/或代理服务器(共享缓存)。如果您根本不希望第 3 方代理缓存您的内容,并且希望每个请求都由您的 Varnish(或您的 Rails 后端)提供服务,您必须从 Varnish 发送适当的 Cache-Control 标头。
Modifying Cache-Control header sent by the backend is discussed in detail at https://www.varnish-cache.org/trac/wiki/VCLExampleLongerCaching
修改后端发送的 Cache-Control 标头在https://www.varnish-cache.org/trac/wiki/VCLExampleLongerCaching 有详细讨论
You can approach the solution from two different angles. If you wish to define max-age at your Rails backend, for instance to specify different TTL for different objects, you can use the method described in the link above.
您可以从两个不同的角度接近解决方案。如果您希望在 Rails 后端定义 max-age,例如为不同的对象指定不同的 TTL,您可以使用上面链接中描述的方法。
Another solution is to not send Cache-Control headers at all from the backend, and instead define desirable TTLs for objects in varnish vcl_fetch(). This is the approach we have taken.
另一种解决方案是根本不从后端发送 Cache-Control 标头,而是在 varnish vcl_fetch() 中为对象定义所需的 TTL。这是我们采取的方法。
We have a default TTL of 600 seconds in Varnish, and define longer TTLs for pages that are definitely explicitly purged when changes are made. Here's our current vcl_fetch() definition:
我们在 Varnish 中的默认 TTL 为 600 秒,并为在进行更改时明确清除的页面定义了更长的 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;
}
}
In our case we don't send Cache-Control headers at all from the web backend servers.
在我们的例子中,我们根本不从 Web 后端服务器发送 Cache-Control 标头。

