【问题标题】:Make varnish serve request from cache (cookies are cleaned)从缓存发出清漆服务请求(cookies被清除)
【发布时间】:2020-07-26 21:48:00
【问题描述】:

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!-- Global site tag (gtag.js) - Google Analytics -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-54516992-1"></script>
    <script>
      window.dataLayer = window.dataLayer || [];
      function gtag(){dataLayer.push(arguments);}
      gtag('js', new Date());

      gtag('config', 'UA-54516992-1');
    </script>

</head>
<body>
    test
</body>
</html>

后端。这是 Python + Django。请不要害怕。我只是在这里设置了一个 cookie (render_to_response),然后我需要一个在断点处停止的地方(在代码下方,它通过注释显示它所在的位置)。

class HomeView(TemplateView):
    template_name = "home/home.html"

    def render_to_response(self, context, **response_kwargs):
        response = super(TemplateView, self).render_to_response(context, **response_kwargs)
        response.set_cookie('sort_on', 'title')
        return response

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        return context # Breakpoint.

varnishd出于学习目的,我只清理所有 cookie。

$ varnishd -V
varnishd (varnish-6.0.6 revision 29a1a8243dbef3d973aec28dc90403188c1dc8e7)
Copyright (c) 2006 Verdens Gang AS
Copyright (c) 2006-2019 Varnish Software AS

VCL

vcl 4.1;

backend default {
    .host = "127.0.0.1";
    .port = "8080";
}

sub vcl_recv {
    call remove_proprietary_cookies;

    if (req.http.Cookie) {      
        return (pass);
    }

}   


sub remove_proprietary_cookies{
    set req.http.Cookie = regsuball(req.http.Cookie, ".*", "");
}

然后我重新加载页面几次以确保 cookie 确实存在。

在 Chrome 中:

document.cookie
"sort_on=title; _ga=GA1.1.988164671.1586849704; _gid=GA1.1.995393496.1586849704; _gat_gtag_UA_54516992_1=1"

cookies 的图片(以上文字的副本):

好的。我们已经检查了 Cookie 是否已设置。现在让我们检查一下 cookie 是否已正确清理。

我在braakpoint 停下来检查cookie。值为 {}。

嗯。所有 cookie 似乎都已清除。

问题: 重新加载时,我经常遇到断点。这意味着 Varnish 将请求传递到后端。换句话说 if (req.http.Cookie) 没有像我预期的那样工作。我希望在上一步中我已经删除了 cookie。然后我检查 cookie 是否存在。而且不应该有。

你能帮帮我吗:

  1. 了解这里发生了什么。

  2. 组织所有内容,这样如果我错误地删除了 cookie,我一定要删除它们。

  3. 让 Varnish 从缓存中处理此请求,而不将其传递到后端。

==============4月16日添加================= ++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++

我已将 Varnish 升级到 6.4:

michael@michael:~$ varnishd -V
varnishd (varnish-6.4.0 revision 13f137934ec1cf14af66baf7896311115ee35598)
Copyright (c) 2006 Verdens Gang AS
Copyright (c) 2006-2020 Varnish Software AS

我们要测试的内容:

  1. 在后端设置 Google Analytics cookie 和 cookie。
  2. 让 Varnish 删除所有 cookie 并缓存响应。
  3. 检查请求是否只传递到后端一次。

然后我在 Varnish 后面组织了 nginx(仅用于记录请求)。 Nginx 在 8090 监听。这是日志配置:

   log_format  main  '[$time_local] $http_cookie';

Cookie:

  1. 我在 HTML 中组织 Google Analytics 的跟踪。
  2. 在后端,我设置了名为“sort_on”的 cookie,其值为“title”。

++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++

如果我们不切 cookie,日志看起来是这样的(这只是为了比较):

127.0.0.1 - - [16/Apr/2020:08:11:05 +0300] "GET / HTTP/1.1" sort_on=title; _ga=GA1.1.236170900.1587013419; _gid=GA1.1.2033785209.1587013419 200 334 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36" "127.0.0.1"

++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++

varnish.ctl

vcl 4.1;
import cookie;

backend default {
    .host = "127.0.0.1";
    .port = "8090";
}


sub vcl_recv {
    unset req.http.Cookie;
    if (req.http.Cookie) {  
        return (pass);
    }   
}

Nginx 将请求传递到后端。后端位于 8080 端口。

简而言之,什么在哪里听:

Varnish - 8000
Nginx - 8090
Backend - 8080

开始清漆:

michael@michael:~$ sudo varnishd -f /home/michael/PycharmProjects/varnish/varnish.vcl -a localhost:8000

打开Chrome,多次加载页面:

Nginx的访问日志:

127.0.0.1 - - [16/Apr/2020:08:12:49 +0300] "GET / HTTP/1.1" - 200 334 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36" "127.0.0.1"
127.0.0.1 - - [16/Apr/2020:08:13:21 +0300] "GET / HTTP/1.1" - 200 334 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36" "127.0.0.1"

我们可以看到没有cookie。没关系。 Cookie 被切断。

问题:请求不可避免地被传递到后端。我总是停在断点处。

您能否就如何处理这个问题给我一些建议?

【问题讨论】:

    标签: varnish varnish-vcl varnish-4


    【解决方案1】:

    Varnish 不查看 Cookie 请求标头的内容,而是检查标头是否存在。

    您需要做的是检查Cookie 标头是否为空,如果是,则删除整个内容。

    只需在 regsub 声明后添加:

    if (req.http.Cookie ~ "^\s*$") {
        unset req.http.Cookie;
    }
    

    让流程更加灵活

    实际上,您可能不会删除所有 cookie,而只会删除对您的应用程序不重要的那些。

    您可以使用此语句删除所有 cookie,除了您的应用程序需要的那些:

    sub vcl_recv {
      if (req.http.Cookie) {
        set req.http.Cookie = ";" + req.http.Cookie;
        set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
        set req.http.Cookie = regsuball(req.http.Cookie, 
            ";(SESS[a-z0-9]+|NO_CACHE)=", "; \1=");
        set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
        set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");
    
        if (req.http.Cookie ~ "^\s*$") {
          unset req.http.Cookie;
        }
        else {
          return (pass);
        }
      }
    }
    

    此 sn-p 将删除所有 cookie,期望匹配 SESS[a-z0-9]+|NO_CACHE 正则表达式的那些。

    使用vmod_cookie

    在 Varnish 中有一种更简洁的方法来处理 cookie 替换,它涉及在 Varnish 中使用 vmod_cookie 模块。你可以在这里找到它:https://github.com/varnishcache/varnish-cache/tree/master/lib/libvmod_cookie

    如果您升级到 Varnish6.4 版vmod_cookie 将成为核心 Varnish 安装的一部分。

    这相当于使用vmod_cookie:

    vcl 4.1;
    import cookie;
    
    sub vcl_recv {
        cookie.parse(req.http.cookie);
        cookie.keep_re("SESS[a-z0-9]+,NO_CACHE");
        set req.http.cookie = cookie.get_string();
        if (req.http.cookie ~ "^\s*$") {
            unset req.http.cookie;
        }
    }
    

    【讨论】:

    • 谢谢。我需要一些时间来尝试一下。那我很乐意接受你的回答。
    • 亲爱的 Thijs,很遗憾我没能解决这个问题。我已经编辑了我最初的问题。我试过你的 VCL 设置。结果是一样的:后端总是被命中。然后为简单起见,只需删除所有 cookie。你能看看 4 月 16 日添加的内容吗?
    • Cookie 标头是 Varnish 不想缓存的原因之一。还有很多其他原因。最简单的查找方法是使用varnishlog。请在开始之前确保您有一个新鲜缓存,然后将以下命令的输出发送给我:varnishlog -g request -q "ReqUrl eq '/'",假设逻辑在主页上。根据输出,我可以弄清楚发生了什么。请阅读我关于varnishlog 的博文以供参考:feryn.eu/blog/varnishlog-measure-varnish-cache-performance
    • 非常感谢您的回答。问题是在服务器上我设置了一个 cookie。因此浏览器有一个请求,cookie被Varnish截断,然后请求被传递到后端,在后端设置了一个cookie。并且不会缓存带有 cookie 的响应。这就是为什么缓存总是空的。
    猜你喜欢
    • 2012-02-19
    • 2017-10-20
    • 1970-01-01
    • 2012-04-28
    • 1970-01-01
    • 2015-10-10
    • 2012-03-02
    • 2022-11-28
    • 2018-11-22
    相关资源
    最近更新 更多