如何使用Cache-Control控制Varnish和浏览器:Rails环境中的max-age标头?

Geo*_*ieF 22 caching ruby-on-rails varnish http-headers

最近我在Rails应用程序堆栈中添加了一个Varnish实例.可以通过使用Cache-Control Header缓存某个资源来确定其中的Varnish的默认配置,如下所示:

Cache-Control: max-age=86400, public=true
Run Code Online (Sandbox Code Playgroud)

我使用控制器中的expires_in语句实现了那个:

def index
  expires_in 24.hours, public: true
  respond_with 'some content'
end
Run Code Online (Sandbox Code Playgroud)

这很好用.我没想到的是,Cache-Control标头也会影响浏览器.这导致了 - Varnish和我的用户浏览器都缓存某个资源的问题.资源将从varnish中正确清除,但除非达到max-age,否则浏览器不会再次尝试请求它.

所以我想知道我应该将'expires_in'与Varnish结合使用吗?我可以在Varnish前面的Nginx或Apache实例中过滤Cache-Control标头,但这看起来很奇怪.

任何人都可以开导我吗?

问菲利克斯

Ket*_*ola 13

这实际上是一个非常好的有效问题,也是一个非常常见的反向代理问题.

问题是只有一个Cache-Control属性,它适用于客户端浏览器(私有缓存)和/或代理服务器(共享缓存).如果您不希望第三方代理完全缓存您的内容,并希望每个请求都由您的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;
  }
}
Run Code Online (Sandbox Code Playgroud)

在我们的例子中,我们根本不从Web后端服务器发送Cache-Control头.

  • 你也可以使用s-maxage.但是,如果您的用户坐在透明代理(一些ISP仍然使用它们)后面,他们也会看到缓存版本长达24小时.如果需要,可以使用s-maxage.如果没有,那么你应该从你的VCL中的响应中设置缓存控制头.我将编辑我的答案以提及s-maxage. (4认同)
  • 谢谢你的详细解答.我们通过简单地将Cache-Control标头更改为:Cache-Control:max-age = 0 s-maxage = 86400,public = true解决了这个问题,因此浏览器不会缓存资源,而是像Varnish那样共享缓存.那是错的吗? (3认同)
  • 确实.s-maxage绝对是最简单的方法.确保从vcl_deliver中的Cache-Control标头中删除s-maxage,以防止下游缓存使用它.您可以使用regsub过滤它.如果在后端设置s-maxage和max-age,您将获得一个非常灵活的系统,允许您为Varnish和客户端设置不同的TTL,同时避免在VCL代码中使用硬编码的TTL. (3认同)