清漆哈希函数,用于从同一缓存提供 SSR 和 AJAX 调用



我们使用 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参数,其中:/levelsHOSTfoobarde。此外,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, */*就可以解决问题。

最新更新