我使用devicedetect.vcl
将X-UA-Device
标头发送到我的应用,因此它知道要呈现的布局。清漆将为此标头设置的可能值为mobile
或desktop
。
在出路时,此标头会转换为Vary: User-Agent
。
现在,作为一个单独的独立项目,我需要在resp
对象上设置另一个标头(在将其发送到客户端之前将其发送到我们的Golang代理)。此标头将被称为X-Analytics-Device
,其可能的值为bot
,mobile
,tablet
或desktop
。
后端服务器不需要对X-Analytics-Device
执行任何操作。只有我们的Go代理才会解析然后删除此标头,然后再将其发送给客户端。
问题是,我需要根据X-Analytics-Device
中子例程call devicedetect;
的结果设置vcl_recv
标头。我需要最终在resp
vcl_deliver
上设置它,我需要知道传递数据的最佳方式。
我能想到的唯一可行的方法(基于我对Varnish的有限理解),是我需要设置一些其他标题,然后再访问它。
也许是这样的(我现在遗漏了bot
):
if (req.http.X-UA-Device ~ "^mobile") {
set req.http.X-UA-Device = "mobile";
set req.http.X-Analytics-Device = "mobile";
} elseif (req.http.X-UA-Device ~ "^tablet") {
set req.http.X-UA-Device = "desktop";
set req.http.X-Analytics-Device = "tablet";
} else {
set req.http.X-UA-Device = "desktop";
set req.http.X-Analytics-Device = "desktop";
}
在此之后......我不知道。我是否需要在vcl_deliver
?
set resp.http.X-Analytics-Device = req.http.X-Analytics-Device;
如何从resp
传递到req
?如果它被击中或未命中会发生什么?那有关系吗?这是否会尝试在清漆中缓存此标题(显然不应该这样)?
我这样做的主要担心是有很多动人的作品,我不知道最好的方法。
最终的结果是......每个请求都需要检查设备,并且在出路时需要设置标头,而不是将该值与清漆中的数据一起缓存,并且它不会发送它到后端,不需要它。
在我添加上面的伪代码行之前,这是我的完整VCL。
vcl 4.0;
backend default {
.host = "127.0.0.1";
.port = "8080";
}
import std;
include "purge.vcl";
include "devicedetect.vcl";
acl purge {
"localhost";
"127.0.0.1";
"10.0.0.0"/8;
}
sub vcl_recv {
call devicedetect;
if (req.http.X-UA-Device ~ "^mobile") {
set req.http.X-UA-Device = "mobile";
} else {
set req.http.X-UA-Device = "desktop";
}
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.method !~ "^(GET|HEAD|PUT|POST|OPTIONS|DELETE)$") {
return (synth(405));
}
# never cache anything except GET/HEAD
if (req.method != "GET" && req.method != "HEAD") {
return (pass);
}
# don't cache images or assets
if (req.url ~ "\.(js|css|jpg|jpeg|png|gif|ico|tiff|tif|bmp|svg)$") {
return (pass);
}
# fix up the request
unset req.http.cookie;
return (hash);
}
sub vcl_backend_response {
set beresp.do_stream = false;
# device detect
if (bereq.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";
}
}
# bypass cache for files > 5 MB
if (std.integer(beresp.http.Content-Length, 0) > 5242880) {
set beresp.uncacheable = true;
set beresp.ttl = 120s;
return (deliver);
}
# catch obvious reasons we can't cache
if (beresp.http.Set-Cookie) {
set beresp.ttl = 0s;
}
# avoid caching error responses (1m grace period)
if (beresp.status >= 500) {
set beresp.ttl = 1m;
return (deliver);
}
# set times
set beresp.ttl = 24h;
set beresp.grace = 4h;
return (deliver);
}
sub vcl_deliver {
# device detect
if ((req.http.X-UA-Device) && (resp.http.Vary)) {
set resp.http.Vary = regsub(resp.http.Vary, "X-UA-Device", "User-Agent");
}
# remove junk headers
unset resp.http.Server;
unset resp.http.Via;
unset resp.http.X-Powered-By;
unset resp.http.X-Runtime;
unset resp.http.X-Varnish;
if (obj.hits > 0) {
set resp.http.X-Cache = "HIT";
} else {
set resp.http.X-Cache = "MISS";
}
}
答案 0 :(得分:3)
此链接实际上完美地澄清并回答了我未能阐明的所有事情...... https://info.varnish-software.com/blog/adding-headers-gain-insight-vcl
答案是将您需要的所有数据部分放入req
中的vcl_recv
标头中,然后将其复制到vcl_deliver
中的响应中。
他陈述了以下内容,说明为什么它不会被缓存:
由于req对象未传递给客户端,我们需要将req对象中的数据复制到resp。我们在交付时这样做。如果你在vcl_backend_response中执行它,标题将存储在缓存中,这可能不是你想要的。
答案 1 :(得分:0)
@Tallboy的答案救了我的一天。总结一下你想做的是:
# set the value in vcl_recv
sub vcl_recv {
set req.http.X-NAVO-AY = "AYAYAYAYAYAYYYYY";
}
# copy the value from req to resp (because it is not done automatically)
sub vcl_deliver {
set resp.http.X-NAVO-AY = req.http.X-NAVO-AY;
}