5

我不知道我在做什么了。我有很多问题我不知道从哪里开始。这是我的配置:

varnishd (varnish-3.0.3 revision 9e6a70f)
Server version: Apache/2.2.22 (Unix)
Symfony 2.3.1

首先,我AppCache在 app.php 文件中禁用了 Symfony,该文件用作反向代理而不是 Varnish。

这是我的清漆配置:

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;
}

Varnish 删除了公共页面的所有 Cookie 并点击了缓存,这很好但是......由于 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;
}

我不知道如何管理 Symfony 的会话 cookie。因为我在需要用户会话的每个页面上都有一个 facebook 连接按钮。而且因为 Symfony 甚至为匿名用户创建了一个 cookie,所以我对所有请求都有会话 cookie。

帮助将不胜感激:)

谢谢,马克西姆


更新:推荐后的新 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>调用/_fragmenturl。

主页上呈现的 ESI 块不正确(它显示登录 url,就好像用户没有登录一样)但是如果我/_fragment直接调用,返回的块是正确的(带有用户信息)。

我真的不知道它来自哪里,但我很接近:)

4

1 回答 1

5

从入站请求中删除 Cookie 标头会将其从所有生成的 ESI 包含请求中删除。由于您希望访问包含资源中的 cookie 标头,而不是缓存的父项,请尝试以下操作:

if (!(req.url ~ "^/dashboard/") && 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;
} 

这会从对父页面的请求中去除浏览器 cookie,但会将其重新添加到由返回页面中的 esi:include 标记产生的 esi 请求中。我没有对上面的代码进行 lint,所以它可能不是 100% 完美的。

更新

在 vcl_recv 中,如果您不想缓存或递归 esi 处理 esi 片段,您可以将第二个 if 块更改为:

if (!(req.url ~ "^/dashboard/") && req.esi_level > 0 ) {
    set req.http.Cookie = req.http.Esi-Cookie;
    return (pass);
} 
于 2013-07-17T23:42:40.230 回答