Я использую 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";
}
}