Varnish 哈希函数服务于来自同一缓存的 SSR 和 AJAX 调用

Varnish Hash function to serve both SSR and AJAX call from the same cache

我们正在使用 Varnish 缓存代理(在 docker 容器中)来为 SSR 和 AJAX 请求提供服务。目标是让共享缓存(用于注销)用户独立于他们访问数据的方式。选项是 Nuxt (SSR) 或浏览器中的 AJAX 调用(通过 Axios)。浏览器向 https://api.foobar.tld/levels 发出请求,而 SSR 向位于 http://api-foobar-cache-proxy/levels 的内部 docker 容器发出请求。 这主要是有效的,除非它不起作用(案例 4,在日志中)。问题是为什么?

Varnish 使用以下(自定义)哈希函数:

    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:OPTIONS不缓存,只GET请求

预期命中率: 2、6:来自缓存

意想不到的小姐: 4:为什么?对于所有这些 3 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 Platform,它可以响应不同的内容类型。前任。如果您在浏览器中请求 /levels,它将提供 Swagger UI,但是如果您使用 Accept: application/json 请求,它将提供 JSON 版本。将 SSR(模仿 cURL)请求上的接受 header 从 */* 更改为 application/json, */* 就成功了。