我不知道我在做什么。我有很多问题,我不知道从哪里开始。 这里是我的配置:Symfony ESI在启用Cookies时打破清漆缓存
varnishd (varnish-3.0.3 revision 9e6a70f)
Server version: Apache/2.2.22 (Unix)
Symfony 2.3.1
我第一次在其作为反向代理,而不是清漆app.php文件禁用的Symfony AppCache
。
这里是我的光油配置:
Varnish (80) <--> Apache (8080)
# /etc/varnish/default.vcl
backend default {
.host = "127.0.0.1";
.port = "8080";
}
sub vcl_recv {
if (req.http.Cache-Control ~ "no-cache") {
return (pass);
}
if (!(req.url ~ "^/dashboard/")) {
unset req.http.Cookie;
}
# Remove has_js and Google Analytics __* cookies.
set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_[_a-z]+|has_js)=[^;]*", "");
# Remove a ";" prefix, if present.
set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", "");
#set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(__[a-z]+|has_js)=[^;]*", "");
set req.http.Surrogate-Capability = "abc=ESI/1.0";
if (req.restarts == 0) {
if (req.http.x-forwarded-for) {
set req.http.X-Forwarded-For =
req.http.X-Forwarded-For + ", " + client.ip;
} else {
set req.http.X-Forwarded-For = client.ip;
}
}
if (req.request != "GET" &&
req.request != "HEAD" &&
req.request != "PUT" &&
req.request != "POST" &&
req.request != "TRACE" &&
req.request != "OPTIONS" &&
req.request != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}
f (req.request != "GET" && req.request != "HEAD") {
/* We only deal with GET and HEAD by default */
return (pass);
}
if (req.http.Authorization) {
/* Not cacheable by default */
return (pass);
}
return (lookup);
}
sub vcl_pipe {
return (pipe);
}
sub vcl_pass {
return (pass);
}
sub vcl_hash {
hash_data(req.url);
if (req.http.host) {
hash_data(req.http.host);
} else {
hash_data(server.ip);
}
return (hash);
}
sub vcl_fetch {
if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
unset beresp.http.Surrogate-Control;
set beresp.do_esi = true;
}
# Varnish determined the object was not cacheable
if (beresp.ttl <= 0s) {
set beresp.http.X-Varnish-Cacheable = "NO:Not Cacheable";
# You don't wish to cache content for logged in users
} elsif (req.http.Cookie ~ "(UserID|_session)") {
set beresp.http.X-Varnish-Cacheable = "NO:Got Session";
return(hit_for_pass);
# You are respecting the Cache-Control=private header from the backend
} elsif (beresp.http.Cache-Control ~ "private") {
set beresp.http.X-Varnish-Cacheable = "NO:Cache-Control=private";
return(hit_for_pass);
# Varnish determined the object was cacheable
} else {
set beresp.http.X-Varnish-Cacheable = "YES";
}
if (beresp.status >= 300) {
return (hit_for_pass);
}
if (beresp.http.Pragma ~ "no-cache" ||
beresp.http.Cache-Control ~ "no-cache" ||
beresp.http.Cache-Control ~ "private") {
return (hit_for_pass);
}
return (deliver);
}
sub vcl_hit {
return (deliver);
}
sub vcl_deliver {
if (obj.hits > 0) {
set resp.http.X-Varnish-Cached = "HIT";
} else {
set resp.http.X-Varnish-Cached = "MISS";
}
return (deliver);
}
sub vcl_error {
set obj.http.Content-Type = "text/html; charset=utf-8";
set obj.http.Retry-After = "5";
synthetic {"
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>"} + obj.status + " " + obj.response + {"</title>
</head>
<body>
<h1>Error "} + obj.status + " " + obj.response + {"</h1>
<p>"} + obj.response + {"</p>
<h3>Guru Meditation:</h3>
<p>XID: "} + req.xid + {"</p>
<hr>
<p>Varnish cache server</p>
</body>
</html>
"};
return (deliver);
}
sub vcl_init {
return (ok);
}
sub vcl_fini {
return (ok);
}
因为:
if (!(req.url ~ "^/dashboard/")) {
unset req.http.Cookie;
}
光油消除公共页面的所有Cookies和命中缓存,这是很好的,但... 由于Varnish删除了所有无法管理保持登录状态的cookie(没有会话cookie表示没有会话)。
我有一个没有缓存头的ESI块的登录按钮,但这仍然不能解决它。 这里是前端控制器:
public function indexAction()
{
$response = $this->render('AcmeCoreBundle:Default:index.html.twig');
$response->setSharedMaxAge(21600); // 6 hours
return $response;
}
模板扩展layout.html.twig
:
<html lang="en-US">
<head>
...
</head>
<body>
...
<div class="top-right">
{{ render_esi(controller('AcmeUserBundle:Default:loginBox')) }}
</div>
...
</body>
和控制器AcmeUserBundle:Default:loginBox
:
public function loginBoxAction()
{
$response = $this->render('AcmeUserBundle:Block:home_login.html.twig');
$response->setVary('Cookies', false);
$response->setMaxAge(0);
$response->setPrivate();
return $response;
}
我不知道如何管理会话cookie为Symfony。因为我在每个页面上都有一个Facebook连接按钮,所以我需要用户会话。而且由于Symfony甚至为匿名用户创建了一个cookie,所以我对所有请求都有会话cookie。
帮助将不胜感激:)
感谢, 马克西姆
UPDATE:新的VCL文件后,建议:
...
sub vcl_recv {
if (!(req.url ~ "^/dashboard") && !(req.url ~ "^/logout") && !(req.url ~ "^/_fragment") && req.esi_level == 0) {
set req.http.Esi-Cookie = req.http.Cookie;
unset req.http.Cookie;
}
if (!(req.url ~ "^/dashboard") && req.esi_level > 0) {
set req.http.Cookie = req.http.Esi-Cookie;
}
# Remove has_js and Google Analytics __* cookies.
set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_[_a-z]+|has_js)=[^;]*", "");
# Remove a ";" prefix, if present.
set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", "");
# Force ESI capability header
set req.http.Surrogate-Capability = "abc=ESI/1.0";
if (req.restarts == 0) {
if (req.http.x-forwarded-for) {
set req.http.X-Forwarded-For =
req.http.X-Forwarded-For + ", " + client.ip;
} else {
set req.http.X-Forwarded-For = client.ip;
}
}
if (req.request != "GET" &&
req.request != "HEAD" &&
req.request != "PUT" &&
req.request != "POST" &&
req.request != "TRACE" &&
req.request != "OPTIONS" &&
req.request != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}
# if Authorization or no-cache header we skip the cache
if (req.http.Authorization || req.http.Cache-Control ~ "no-cache") {
return (pass);
}
# If not GET or HEAD request we skip the cache
if (req.request != "GET" && req.request != "HEAD") {
return (pass);
}
return (lookup);
}
...
sub vcl_fetch {
if (!(req.url ~ "^/dashboard") && !(req.url ~ "^/login_check")) {
unset beresp.http.set-cookie;
}
if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
unset beresp.http.Surrogate-Control;
set beresp.do_esi = true;
}
# Varnish determined the object was not cacheable
if (beresp.ttl <= 0s) {
set beresp.http.X-Varnish-Cacheable = "NO:Not Cacheable";
# You don't wish to cache content for logged in users
} elsif (req.http.Cookie ~ "(UserID|_session)") {
set beresp.http.X-Varnish-Cacheable = "NO:Got Session";
return(hit_for_pass);
# You are respecting the Cache-Control=private header from the backend
} elsif (beresp.http.Cache-Control ~ "private") {
set beresp.http.X-Varnish-Cacheable = "NO:Cache-Control=private";
return(hit_for_pass);
# Varnish determined the object was cacheable
} else {
set beresp.http.X-Varnish-Cacheable = "YES";
}
if (beresp.status >= 300) {
return (hit_for_pass);
}
if (beresp.http.Pragma ~ "no-cache" ||
beresp.http.Cache-Control ~ "no-cache" ||
beresp.http.Cache-Control ~ "private") {
return (hit_for_pass);
}
return (deliver);
}
每一个公共页面,这就是缓存正确。我在登录页面的任何地方都有缓存HIT,但现在不是什么大问题。
我遇到的问题是在标题中的ESI块。我可以在apache访问日志中看到清漆请求<esi:include>
调用/_fragment
url。
在主页上呈现的ESI块不正确(它显示登录网址,就好像用户没有登录一样),但是如果我直接调用/_fragment
,则返回的块是正确的(包含用户信息)。
我真的不知道它的来自哪里,但我如此接近:)
感谢队友。由于Symfony即使对匿名用户也创建会话cookie,您认为为登录用户创建第二个cookie可能是解决方案吗?如果'logged_in' Cookie存在不会取消设置cookie,否则取消设置Cookie。这会导致匿名用户登录用户的Cache MISS和Cache HIT。你怎么看? – maxwell2022
检查清漆请求的cookie标头,确保您的VCL正确设置它。当直接敲击/ _fragment资源时,请检查响应头以确保它们显式不可缓存(或者如我在更新中所建议的那样为esi请求返回(传递)) –