caching - Varnish 在请求中混合用户代理

标签 caching varnish varnish-vcl

我刚刚安装了 varnish,我正在使用 http://github.com/varnish/varnish-devicedetect检测设备并向用户提供不同的内容。它运作良好,但有时我最终会得到与设备不同的用户代理!例如:当我从安卓设备浏览我的网站时,我有时会得到一个 pc 的用户代理!

我试过检查我的 vcl 寻找错误,但我无法弄清楚。

还有一件事:

我在路由器后面,网络上还有其他用户打开该站点(可能是同一页面)。我们只有一个公共(public) ip,每个人都被分配一个本地 ip。
情况并非如此,它随机选择不同的用户代理,而不仅仅是本地设备。

varnish 如何区分从同一个 ip 到同一个页面的两个请求?

编辑:我的 vcl 代码

import throttle;
import redis;

include "devicedetect.vcl"; #https://raw.githubusercontent.com/varnish/varnish-devicedetect/master/devicedetect.vcl

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

acl admin_ip {
   "XXX.XXX.XXX.XXX";
}

sub vcl_init {

# By default, the redis module will attempt to connect to a Redis server
# at 127.0.0.1:6379 with a connect timeout of 200 milliseconds.

# The function redis.init_redis(host, port, timeout_ms) may be used to
# connect to an alternate Redis server or use a different connect timeout.

   redis.init_redis("localhost", 6379, 200);  /* default values */
}

sub vcl_recv {
   call devicedetect;
   if (req.request == "PURGE") {
        if (!client.ip ~ admin_ip) {
            error 405 "You can't do this, muggle!";
        }
            return(lookup);
   }  
   if(throttle.is_allowed("ip:" + client.ip, "2000req/10m") > 0s) {
                    redis.send("SELECT 5");
                    redis.send("SADD blacklist " + client.ip);
                    error 429 "Too many requests";
   }
  }

  # Use anonymous, cached pages if all backends are down.
  if (!req.backend.healthy) {
    unset req.http.Cookie;
  }

  set req.http.X-Forwarded-For = client.ip;

  if (
      req.url ~ "^/admin$" ||
      req.url ~ "^/admin/.*$" ||
      req.url ~ "^/blog/wp-admin/" ||
      req.url ~ "^/blog/wp-login.php" ||
      req.url ~ "^/blog/wp-admin/.*$") {
       return (pass);
  }  

  if (req.url ~ "(?i)\.(pdf|asc|dat|txt|doc|xls|ppt|tgz|csv|png|gif|jpeg|jpg|ico|swf|css|js)(\?.*)?$") {
    unset req.http.Cookie;
    unset req.http.Cache-Control;
    unset req.http.Max-Age;
    unset req.http.Pragma;
    unset req.http.Cookie;
  }
  if(req.http.Cookie) {
     if (req.http.Cookie !~ "(sessionid|XXXid)" ) {
       remove req.http.Cookie;
     }
  }

}

sub vcl_fetch {
   set beresp.http.X-UA-Device = req.http.X-UA-Device;
   #unset beresp.http.expires; # for cloudfront since it prefers cache-control
                              # header over expires

   if (req.url ~ "(?i)\.(pdf|asc|dat|txt|doc|xls|ppt|tgz|csv|png|gif|jpeg|jpg|ico|swf|css|js)(\?.*)?$") {
    unset beresp.http.set-cookie;
   }
   if (req.http.Content-Type ~ "(image|audio|video|pdf|flash)") {
        set beresp.do_gzip = false;
   }
   if (req.http.Content-Type ~ "text") {
        set beresp.do_gzip = true;
   }
  # Varnish determined the object was not cacheable
    if (beresp.ttl <= 0s) {
        set beresp.http.X-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-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-Cacheable = "NO:Cache-Control=private";
        return(hit_for_pass);

    # Varnish determined the object was cacheable
    } else {
        set beresp.http.X-Cacheable = "YES";
    }
  if (req.backend.healthy) {
        set req.grace = 10m;
  } else {
        set req.grace = 1h;
  }
  return (deliver);
}

sub vcl_fetch {
     if (beresp.ttl <= 0s ||
         beresp.http.Set-Cookie ||
         beresp.http.Vary == "*") {
               /*
                * Mark as "Hit-For-Pass" for the next 2 minutes
                */
               set beresp.ttl = 120 s;
               return (hit_for_pass);
     }
     set beresp.grace = 1h;
     return (deliver);
}

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_hit {
     if (req.request == "PURGE"){
        set obj.ttl = 0s;
        error 200 "Varnish cache has been purged for this object.";
     }
     return (deliver);
}

sub vcl_miss {
     if (req.request == "PURGE") {
        error 404 "Object not in cache.";
     } 
     return (fetch);
}


sub vcl_deliver {
  #std.log("DEV: Hits on " + req.url + ": " + obj.hits);

  if (obj.hits > 0) {
    set resp.http.X-Varnish-Cache = "HIT";
  }
  else {
    set resp.http.X-Varnish-Cache = "MISS";
  }

  return (deliver);
}

sub vcl_error {
  # Redirect to some other URL in the case of a homepage failure.
  #if (req.url ~ "^/?$") {
  #  set obj.status = 302;
  #  set obj.http.Location = "http://backup.example.com/";
  #}

  # Otherwise redirect to the homepage, which will likely be in the cache.
  set obj.http.Content-Type = "text/html; charset=utf-8";
  synthetic {"
<html>
<head>
  <title>Error "} + obj.status + {" </title>
  <style>
    body { background: #FFF; text-align: center; color: black; }
    #page { border: 1px solid #CCC; width: 500px; margin: 100px auto 0; padding: 30px; background: f2f2f2; }
    .error { color: #222; }
  </style>
</head>
<body>
  <div id="page">
    <h1 class="title">Error "} + obj.status + " " + obj.response + {"</h1>
    <p>The page you requested may be temporarily unavailable.</p>
    <p>Message blah blah!</p>
  </div>
</body>
</html>
"};
  return (deliver);
}

最佳答案

您应该首先查看 installation documentation用于 Varnish 设备检测。根据后端的配置方式,您可以使用文档中列出的任何示例。

最简单的情况(示例 1)是添加 X-UA-Device Vary 的标题 header ,以便为不同设备提供的不同内容被唯一地缓存。请注意,Varnish 使用 Vary独立于 vcl_hash() , 所以你不需要添加 VaryX-UA-Device header 来散列自己( reference )。

这是文档中的注释示例(上面的链接)以供引用。

include "devicedetect.vcl";
sub vcl_recv { call devicedetect; }
# req.http.X-UA-Device is copied by Varnish into bereq.http.X-UA-Device

# so, this is a bit conterintuitive. The backend creates content based on the normalized User-Agent,
# but we use Vary on X-UA-Device so Varnish will use the same cached object for all U-As that map to
# the same X-UA-Device.
# If the backend does not mention in Vary that it has crafted special
# content based on the User-Agent (==X-UA-Device), add it.
# If your backend does set Vary: User-Agent, you may have to remove that here.
sub vcl_fetch {
    if (req.http.X-UA-Device) {
        if (!beresp.http.Vary) { # no Vary at all
            set beresp.http.Vary = "X-UA-Device";
        } elseif (beresp.http.Vary !~ "X-UA-Device") { # add to existing Vary
            set beresp.http.Vary = beresp.http.Vary + ", X-UA-Device";
        }
    }
    # remove comment for testing, be careful to use this in prod
    # Google might be worried about crafted content
    # set beresp.http.X-UA-Device = req.http.X-UA-Device;
}

# to keep any caches in the wild from serving wrong content to client #2 behind them, we need to
# transform the Vary on the way out.
sub vcl_deliver {
    if ((req.http.X-UA-Device) && (resp.http.Vary)) {
        set resp.http.Vary = regsub(resp.http.Vary, "X-UA-Device", "User-Agent");
    }
}

关于caching - Varnish 在请求中混合用户代理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25380071/

相关文章:

正则表达式以匹配主机请求

varnish - VCL 返回(查找)

python - Python中使用优先级队列实现LRU缓存

java - 使用来自依赖 jar 的 Spring CacheManager

tomcat - mod_cache 返回 "broken expires header"

drupal - Varnish 缓存 - 如何仅为主页清除/删除缓存

varnish - 升级到 Varnish v4

asp.net-mvc - 网络农场中的 nHibernate 策略

Varnish :有条件地清除缓存以确保资源是最新的

regex - 如何用 Varnish 添加尾部斜杠?