我们使用 Varnish Cache 代理(在 docker 容器中)来为 SSR 和 AJAX 请求提供服务。目标是让共享缓存(用于注销)用户独立于他们访问数据的方式。选项是Nuxt(SSR)或浏览器中的AJAX调用(通过Axios)。浏览器向 https://api.foobar.tld/levels 发出请求,而 SSR 在 http://api-foobar-cache-proxy/levels 时向内部 docker 容器发出请求。 这大多有效,除非它不起作用(日志中的情况 4)。问题是为什么?
清漆使用以下(自定义)哈希函数:
sub vcl_hash {
hash_data(req.url);
std.log("X-DEBUG-url:" + req.url);
if (req.http.Origin ~ "foobar") {
hash_data("HOSTfoobar");
std.log("X-DEBUG-host:1-HOSTfoobar");
} elseif (req.http.host ~ "foobar") {
hash_data("HOSTfoobar");
std.log("X-DEBUG-host:2-HOSTfoobar");
}
if (req.http.Locale) {
hash_data(req.http.Locale);
std.log("X-DEBUG-locale:1-" + req.http.Locale);
} else {
hash_data("de");
std.log("X-DEBUG-locale:2-de");
}
return (lookup);
}
调试日志:varnishncsa -F '"%r" %{Varnish:handling}x %{VCL_Log:X-DEBUG-url}x %{VCL_Log:X-DEBUG-host}x %{VCL_Log:X-DEBUG-locale}x' | grep "/levels"
输出:
1: "GET http://api-foobar-cache-proxy/levels HTTP/1.1" miss /levels 1-HOSTfoobar 1-de // SSR first call (miss, expected, cold cache)
2: "GET http://api-foobar-cache-proxy/levels HTTP/1.1" hit /levels 1-HOSTfoobar 1-de // SSR second call (hit, expected)
3: "OPTIONS https://api.foobar.tld/levels HTTP/1.1" pass /levels 1-HOSTfoobar 2-de // Browser OPTIONS call (miss, expected)
4: "GET https://api.foobar.tld/levels HTTP/1.1" miss /levels 1-HOSTfoobar 1-de // Browser first call (miss, not expected)
5: "OPTIONS https://api.foobar.tld/levels HTTP/1.1" pass /levels 1-HOSTfoobar 2-de // Browser OPTIONS call (miss, expected)
6: "GET https://api.foobar.tld/levels HTTP/1.1" hit /levels 1-HOSTfoobar 1-de // Browser second call (hit, expected)
预期未命中:1:冷缓存
预期通过:3、5:不缓存选项,仅缓存 GET 请求
命中预期:2、6:从缓存
意外小姐:4:为什么? 对于所有这些hash_data
参数,其中:/levels
,HOSTfoobar
和de
。此外,return (lookup)
应该防止内置vcl_hash
,除非我完全错了。
请求的varnishlog
的一些附加调试输出: 比较请求的varnishlog
。完整的日志可以在这里找到,https://0bin.net/paste/2UYa-YSr#ykSOg11iJxJXA-CsUiK4es1gGekUDN4VL3wqVA9Jqdv,相关部分(?):
请求 1:
[...]
- VCL_call HASH
- VCL_Log X-DEBUG-url:/levels
- VCL_Log X-DEBUG-host:1-HOSTfoobar
- VCL_Log X-DEBUG-locale:1-de
- VCL_return lookup
- VCL_call MISS
- ReqHeader x-cache: miss
- VCL_return fetch
- Link bereq 32771 fetch
[...]
请求 2:
[...]
- VCL_call HASH
- VCL_Log X-DEBUG-url:/levels
- VCL_Log X-DEBUG-host:1-HOSTfoobar
- VCL_Log X-DEBUG-locale:1-de
- VCL_return lookup
- Hit 32771 3585.968366 3600.000000 0.000000
- VCL_call HIT
[...]
请求 4:
[...]
- VCL_call HASH
- VCL_Log X-DEBUG-url:/levels
- VCL_Log X-DEBUG-host:1-HOSTfoobar
- VCL_Log X-DEBUG-locale:1-de
- VCL_return lookup
- VCL_call MISS
- ReqHeader x-cache: miss
- VCL_return fetch
- Link bereq 98318 fetch
[...]
请求 6:
[...]
- VCL_call HASH
- VCL_Log X-DEBUG-url:/levels
- VCL_Log X-DEBUG-host:1-HOSTfoobar
- VCL_Log X-DEBUG-locale:1-de
- VCL_return lookup
- Timestamp Waitinglist: 1636723569.802992 0.183061 0.183061
- Hit 98318 3600.182590 3600.000000 0.000000
- VCL_call HIT
[...]
所以,事实证明,像往常一样,计算机没有任何问题,用户是问题所在。在后端,我使用API平台,它可以以不同的内容类型进行响应。例如,如果您在浏览器中请求/levels
,它将提供 Swagger UI,但是如果您使用Accept: application/json
请求它,它将提供 JSON 版本。将接受标头从 SSR(模仿 cURL)请求上的*/*
更改为application/json, */*
就可以解决问题。