【问题标题】:Varnish 3: Accept JSON returns HTMLVarnish 3:接受 JSON 返回 HTML
【发布时间】:2018-08-02 11:09:52
【问题描述】:

我尝试制作一个 REST-API,但 varnish 总是返回第一个调用的响应,我不知道为什么。

如果我用浏览器打开一个页面,Varnish 返回 HTML -> 没问题。 如果我 curl 同一页面 curl -i https://example.com -H "Accept: application/json" Varnish 也会返回 HTML -> 这是 False。

正如我所见,Varnish 总是返回第一个缓存的项目,如果这是 JSON,varnish 返回 JSON,如果这是 HTML,varnish 返回 HTML。

没有 Varnish,一切都按预期工作。

【问题讨论】:

    标签: varnish


    【解决方案1】:

    如果您在同一个 URL 上提供不同的内容类型,您可能需要告诉 Varnish 相应地对缓存进行分区。

    事实上,Varnish 并没有什么特别之处,它的行为与其他代理一样。如果他们看到的 URL 没有指定资源缓存应如何分区的信息,那么无论是 JSON 还是常规请求,第一个请求都将被缓存并以相同的方式提供服务,而与请求类型无关。

    所以你需要告诉 Varnish 如何为资源分区缓存。

    “变化”标题

    对于其他代理来说,最直接和“HTTP”兼容的方式是Vary response 标头。

    它告诉代理缓存(在本例中为 Varnish)根据来自客户端的标头值对资源进行分区、变化缓存。

    例如客户端发送标头 X: some-value 并且您的应用发送标头 Vary: X 是为了使缓存在 X的不同值之间有所不同>.

    对于 Varnish 3,有一个带有 Accept-Encoding 的示例。

    文章详细介绍了Vary 的实现挑战——不同的客户端可能会为不同的标头发送完全不同的值,从而导致缓存严重分区。因此,您通常希望将可变标头的值标准化为一组已知的预期值。

    在您的情况下,您想要改变(并规范化)Accept header。所以类似于(在vcl_recv 程序中):

    if (req.http.Accept) {
        if (req.http.Accept ~ "application/json") {
            set req.http.Accept = "application/json";
        } else {
            set req.http.Accept = "text/html";
        }
    }
    

    接下来,您需要让您的应用实际发送Vary: Accept(在您的应用源文件中)。或者,如果修改应用程序源文件不可行,您可以抛出一些 Varnish VCL:

    sub vcl_fetch {
        if (!beresp.http.Vary) { # no Vary at all
            set beresp.http.Vary = "Accept";
        } elseif (beresp.http.Vary !~ "Accept") { # add to existing Vary
            set beresp.http.Vary = beresp.http.Vary + ", Accept";
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-12-29
      • 1970-01-01
      • 1970-01-01
      • 2016-05-18
      • 2016-04-04
      • 2012-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多