liip/cache-control-bundle

此包已被废弃,不再维护。作者建议使用friendsofsymfony/http-cache-bundle包。

此Bundle提供了一种通过应用配置设置基于路径的缓存过期头的方式,并提供了一个控制反向代理Varnish的助手。

安装次数: 124,404

依赖项: 1

建议者: 1

安全性: 0

星标: 109

关注者: 54

分支: 24

开放问题: 0

类型:symfony-bundle

1.0.7 2013-12-19 08:15 UTC

This package is not auto-updated.

Last update: 2022-02-01 12:20:13 UTC


README

此Bundle不再维护。如有需要,请随时进行分支。

CacheControlBundle

此Bundle提供了一种通过应用配置设置基于路径的缓存过期头的方式,并提供了一个控制反向代理Varnish的助手。

Build Status

此Bundle已弃用!

LiipCacheControlBundle已进入维护模式。它已被FOSHttpCacheBundle取代。

请参阅我们的迁移指南,了解如何过渡到新Bundle。

此存储库将继续可用,以避免破坏现有安装,但维护将仅限于最基本。

使用composer安装

只需将以下行添加到项目的composer.json require部分

"liip/cache-control-bundle": "~1.0"

启用模块

将此Bundle添加到应用程序的kernel

// application/ApplicationKernel.php
public function registerBundles()
{
  return array(
      // ...
      new Liip\CacheControlBundle\LiipCacheControlBundle(),
      // ...
  );
}

缓存控制

只需使用给定的缓存控制规则配置所需数量的路径

# app/config.yml
liip_cache_control:
    rules:
        # the controls section values are used in a call to Response::setCache();
        - { path: ^/, controls: { public: true, max_age: 15, s_maxage: 30, last_modified: "-1 hour" }, vary: [Accept-Encoding, Accept-Language] }

        # only match login.example.com
        - { host: ^login.example.com$, controls: { public: false, max_age: 0, s_maxage: 0, last_modified: "-1 hour" }, vary: [Accept-Encoding, Accept-Language] }

        # match a specific controller action
        - { controller: ^AcmeBundle:Default:index$, controls: { public: true, max_age: 15, s_maxage: 30, last_modified: "-1 hour" }, vary: [Accept-Encoding, Accept-Language] }

从上到下尝试匹配,取第一个匹配并应用。

运行 app/console config:dump-reference liip_cache_control 以获取完整的配置选项列表。

关于路径参数

规则的pathhostcontroller参数代表一个页面必须匹配的正规表达式,才能使用该规则。

因此,并且这可能不是你期望的行为,路径^/将匹配任何页面。

如果你只想匹配主页,则需要使用路径^/$

为了匹配具有缓存规则的页面URL,此Bundle使用类Symfony\Component\HttpFoundation\RequestMatcher

unless_role使根据当前认证用户是否被授予提供的角色来跳过规则成为可能。

调试信息

调试参数向每个响应添加一个X-Cache-Debug头,你可以在Varnish配置中使用它。

# app/config.yml
liip_cache_control:
    debug: true

将以下代码添加到Varnish配置中,以便在启用时向响应添加调试头

#in sub vcl_deliver
# debug info
# https://www.varnish-cache.org/trac/wiki/VCLExampleHitMissHeader
if (resp.http.X-Cache-Debug) {
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
        set resp.http.X-Cache-Hits = obj.hits;
    } else {
       set resp.http.X-Cache = "MISS";
    }
    set resp.http.X-Cache-Expires = resp.http.Expires;
} else {
    # remove Varnish/proxy header
    remove resp.http.X-Varnish;
    remove resp.http.Via;
    remove resp.http.X-Purge-URL;
    remove resp.http.X-Purge-Host;
}

自定义Varnish参数

除了默认支持的头之外,你可能还想为Varnish设置自定义缓存头。

# app/config.yml
liip_cache_control:
    rules:
        # the controls section values are used in a call to Response::setCache();
        - { path: /, controls: { stale_while_revalidate=9000, stale_if_error=3000, must-revalidate=false, proxy_revalidate=true } }

自定义Varnish超时时间

Varnish会检查响应的Cache-Control头部来设置TTL。有时你可能希望Varnish缓存你的响应时间比浏览器更长。这样可以通过减少对后端的请求来提高性能。

要实现这一点,你可以为你的规则设置reverse_proxy_ttl选项

# app/config.yml
liip_cache_control:
    rules:
        # the controls section values are used in a call to Response::setCache();
        - { path: /, reverse_proxy_ttl: 300, controls: { public: true, max_age: 15, s_maxage: 30, last_modified: "-1 hour" } }

以下示例将在你的响应中添加头部X-Reverse-Proxy-TTL: 300

但是默认情况下,Varnish将不知道任何事情。为了让它工作,你必须扩展你的Varnish vcl_fetch配置

sub vcl_fetch {

    /* ... */

    if (beresp.http.X-Reverse-Proxy-TTL) {
        C{
            char *ttl;
            ttl = VRT_GetHdr(sp, HDR_BERESP, "\024X-Reverse-Proxy-TTL:");
            VRT_l_beresp_ttl(sp, atoi(ttl));
        }C
        unset beresp.http.X-Reverse-Proxy-TTL;
    }

    /* ... */

}

然后Varnish将查找X-Reverse-Proxy-TTL头部,如果存在,Varnish将使用找到的值作为TTL,然后删除该头部。在VCL中有一个beresp.ttl字段,但不幸的是,它只能设置为绝对值,而不能动态设置。因此,我们必须使用C代码片段。

请注意,如果你使用这个,你应该有一个好的清除策略。

Varnish助手

此助手可以用来与Varnish通信以清除缓存的URL。配置Varnish反向代理的位置(确保不要忘记任何,因为每个Varnish都必须单独通知)

# app/config.yml
liip_cache_control:
    varnish:
        host: http://www.liip.ch
        ips: 10.0.0.10, 10.0.0.11
        port: 80
        headers: ["Authorization: Basic Zm9vOmJhcg==", "X-Another-Header: here"]
  • host:这必须与客户端连接到Varnish时使用的Web主机匹配。如果你打错了,你不会注意到,但缓存清除永远不会发生。你也可以在这里添加正则表达式,如"."以清除所有主机条目。正则表达式将以"^(.)$"结束,在这个例子中,正则表达式将被"^("和")$"包围。
  • ips:你的Varnish服务器IP地址列表。以逗号分隔。
  • port:Varnish正在监听用于传入Web连接的端口。
  • headers:(可选)如果你想在每个发送到Varnish的请求中发送特殊头部,你可以在这里添加它们(作为数组)

要使用Varnish缓存助手,你必须注入liip_cache_control.varnish服务或从服务容器获取它

// using a "manual" url
$varnish = $this->container->get('liip_cache_control.varnish');
/* $response Is an associative array with keys 'headers', 'body', 'error' and 'errorNumber' for each configured IP.
   A sample response will look like:
   array('10.0.0.10' => array('body'    => 'raw-request-body',
                              'headers' => 'raw-headers',
                              'error'   =>  'curl-error-msg',
                              'errorNumber'   =>  integer-curl-error-number),
          '10.0.0.11' => ...)
*/
$response = $varnish->invalidatePath('/some/path');

// using the router to generate the url
$router = $this->container->get('router');
$varnish = $this->container->get('liip_cache_control.varnish');
$response = $varnish->invalidatePath($router->generate('myRouteName'));

当使用ESI时,你可能想要清除单个片段。要生成相应的_internal路由,将http_kernel注入你的控制器,并使用HttpKernel::generateInternalUri,参数与twig render标签中的参数相同。

清除

将以下代码添加到你的Varnish配置中,以便它处理PURGE请求(确保取消注释适当的行)

varnish 3.x

#top level:
# who is allowed to purge from cache
# https://www.varnish-cache.org/docs/trunk/users-guide/purging.html
acl purge {
    "127.0.0.1"; #localhost for dev purposes
    "10.0.11.0"/24; #server closed network
}

#in sub vcl_recv
# purge if client is in correct ip range
if (req.request == "PURGE") {
    if (!client.ip ~ purge) {
        error 405 "Not allowed.";
    }

    return(lookup);
}

sub vcl_hit {
  if (req.request == "PURGE") {
     purge;
     error 200 "Purged";
     return (error);
  }
}

sub vcl_miss {
   if (req.request == "PURGE") {
     purge;
     error 404 "Not in cache";
     return (error);
   }
}

在Varnish 2中,purge动作实际上是只是将缓存标记为无效。这在Varnish 3中称为ban

Varnish 2.x

#top level:
# who is allowed to purge from cache
# https://www.varnish-cache.org/docs/trunk/users-guide/purging.html
acl purge {
    "127.0.0.1"; #localhost for dev purposes
    "10.0.11.0"/24; #server closed network
}

#in sub vcl_recv
# purge if client is in correct ip range
if (req.request == "PURGE") {
    if (!client.ip ~ purge) {
        error 405 "Not allowed.";
    }

    purge("req.url ~ " req.url);
    purge("req.url ~ " req.url);
    error 200 "Success";
}

注意:此代码将使所有域的URL无效。如果你的Varnish为多个域提供服务,你应该改进此配置。

关于Varnish路径清除,相当于这样做

 netcat localhost 6081 << EOF
 PURGE /url/to/purge HTTP/1.1
 Host: webapp-host.name

 EOF

禁止

从Varnish 3开始,可以使用禁止来使缓存无效。禁止使用正则表达式使整个部分无效,所以你需要小心不要使太多无效。

配置Varnish反向代理以使用ban作为清除指令

# app/config.yml
liip_cache_control:
    varnish:
        purge_instruction: ban

这将执行清除请求,并将添加X-Purge头部,这些头部可以被你的Varnish配置使用

varnish 3.x

#top level:
# who is allowed to purge from cache
# https://www.varnish-cache.org/docs/trunk/users-guide/purging.html
acl purge {
    "127.0.0.1"; #localhost for dev purposes
    "10.0.11.0"/24; #server closed network
}

#in sub vcl_recv
# purge if client is in correct ip range
if (req.request == "PURGE") {
    if (!client.ip ~ purge) {
        error 405 "Not allowed.";
    }
    ban("obj.http.X-Purge-Host ~ " + req.http.X-Purge-Host + " && obj.http.X-Purge-URL ~ " + req.http.X-Purge-Regex + " && obj.http.Content-Type ~ " + req.http.X-Purge-Content-Type);
    error 200 "Purged.";
}

#in sub vcl_fetch
# add ban-lurker tags to object
set beresp.http.X-Purge-URL = req.url;
set beresp.http.X-Purge-Host = req.http.host;

强制刷新

或者,也可以使用以下方法强制刷新

#top level:
# who is allowed to purge from cache
# http://www.varnish-cache.org/trac/wiki/VCLExampleEnableForceRefresh
acl refresh {
    "127.0.0.1"; #localhost for dev purposes
    "10.0.11.0"/24; #server closed network
}

sub vcl_hit {
    if (!obj.cacheable) {
        pass;
    }

    if (req.http.Cache-Control ~ "no-cache" && client.ip ~ refresh) {
        set obj.ttl = 0s;
        return (restart);
    }
    deliver;
}

关于Varnish路径强制刷新,相当于这样做

netcat localhost 6081 << EOF
GET /url/to/refresh HTTP/1.1
Host: webapp-host.name
Cache-Control: no-cache, no-store, max-age=0, must-revalidate

EOF

要使用Varnish缓存助手,你必须注入liip_cache_control.varnish服务或从服务容器获取它

// using a "manual" url
$varnish = $this->container->get('liip_cache_control.varnish');
$varnish->refreshPath('/some/path');

从控制台禁止

你还可以从控制台禁止URL

app/console liip:cache-control:varnish:invalidate

将禁止(使无效)所有配置的Varnish服务器中的条目(匹配varnish.host)

app/console liip:cache-control:varnish:invalidate /posts.*

将禁用(使无效)所有配置的 Varnish 服务器中的条目,其中 URL 以 "/posts" 开头。这里可以使用 Varnish 所理解的任何正则表达式。

它使用 Varnish Helper 类,因此如果您在配置文件(varnish.ips)中定义了多个 Varnish 服务器,则将在所有服务器中删除条目。

缓存授权监听器

启用授权监听器

# app/config.yml
liip_cache_control:
    authorization_listener: true

此监听器使得在安全防火墙完成后,可以立即停止带有 200 "OK" 的 HEAD 请求。当处理对部分用户不可用内容时,这非常有用。

在这种情况下,缓存命中时,Varnish 可以配置为在访问此内容时发出 HEAD 请求。这样可以使用 Symfony2 来验证授权,但不需要对已在 Varnish 缓存中的内容进行重新生成的工作。

请注意,这显然意味着它仅与基于路径的安全功能一起工作。在 Controller 内部实现的任何附加安全功能都将被忽略。

此外,请注意,HEAD 响应应包含与同一 URL 的 GET 响应相同的 HTTP 标头元数据。然而,出于本用例的目的,我们别无选择,只能假设为 200。

backend default {
    .host = “127.0.0.1″;
    .port = “81″;
}

acl purge {
    “127.0.0.1″; #localhost for dev purposes
}

sub vcl_recv {
    # pipe HEAD requests as we convert all GET requests to HEAD and back later on
    if (req.request == “HEAD”) {
        return (pipe);
    }


    if (req.request == "GET") {
        if (req.restarts == 0) {
            set req.request = "HEAD";
            return (pass);
        } else {
            set req.http.Surrogate-Capability = "abc=ESI/1.0";
            return (lookup);
        }
    }
}

sub vcl_hash {
}

sub vcl_fetch {
    if (beresp.http.Cache-Control ~ “(private|no-cache|no-store)”) {
        return (pass);
    }

    if (beresp.status >= 200 && beresp.status < 300) {
        if (req.request == "HEAD") {
            # if the BE response said OK, change the request type back to GET and restart
            set req.request = "GET";
            restart;
        }
    } else {
        # In any other case (authentication 302 most likely), just pass the response to the client
        # Don't forget to set the content-length, as the HEAD response doesn't have any (and the client will hang)
        if (req.request == "HEAD") {
            set beresp.http.content-length = "0";
        }

        return (pass);
    }

    if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
        unset beresp.http.Surrogate-Control;
        // varnish < 3.0:
        esi;
        // varnish 3.0 and later:
        // set beresp.do_esi = true;
    }
}

闪存消息监听器

响应闪存消息监听器将所有当前设置的闪存消息移动到一个 cookie 中。这样就可以更好地处理与 ESI 结合的闪存消息。ESI 配置需要忽略配置的 cookie。然后客户端负责读取 cookie,显示闪存消息,并通过 JavaScript 删除闪存消息。

# app/config.yml
liip_cache_control:
    flash_message_listener:
        name: flashes
        path: /
        host: null
        secure: false
        httpOnly: true

如果您不希望使用闪存消息监听器,您可以禁用它。

# app/config.yml
liip_cache_control:
    flash_message_listener:
        enabled: false