liip / cache-control-bundle
此Bundle提供了一种通过应用配置设置基于路径的缓存过期头的方式,并提供了一个控制反向代理Varnish的助手。
Requires
- php: >=5.3.2
- symfony/framework-bundle: ~2.1
Requires (Dev)
- ext-curl: *
Suggests
- ext-curl: Used by Varnish Helper to construct requests.
This package is not auto-updated.
Last update: 2022-02-01 12:20:13 UTC
README
此Bundle不再维护。如有需要,请随时进行分支。
CacheControlBundle
此Bundle提供了一种通过应用配置设置基于路径的缓存过期头的方式,并提供了一个控制反向代理Varnish的助手。
此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
以获取完整的配置选项列表。
关于路径参数
规则的path
、host
和controller
参数代表一个页面必须匹配的正规表达式,才能使用该规则。
因此,并且这可能不是你期望的行为,路径^/
将匹配任何页面。
如果你只想匹配主页,则需要使用路径^/$
。
为了匹配具有缓存规则的页面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