我尝试制作一个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,一切都会按预期进行。
最佳答案
如果您在同一URL上提供不同的内容类型,则可能要告诉Varnish相应地对缓存进行分区。
实际上,Varnish并没有做太多特别的事情,它的行为就像其他代理一样。如果他们看到一个没有指定资源缓存应如何分区的信息的URL,则无论是JSON还是常规请求,第一个请求都将被缓存并提供相同的服务,而与请求类型无关。
因此,您需要告诉Varnish如何对资源进行缓存分区。
“Vary” header
对于其他代理而言,最直接,最“HTTP”兼容的方式是Vary
响应头。
它告诉代理缓存(在这种情况下为Vanish)进行分区,根据来自客户端的 header 值更改资源的缓存。
例如。客户端发送 header X:某值,而您的应用发送 header Vary:X 是使 X 的不同值之间的高速缓存不同的方法。
对于Varnish 3,有一个带有Accept-Encoding的示例。
本文详细介绍了Vary
的实现挑战-不同的客户端可能会为完全不同的 header 发送完全不同的值,从而导致严重分区的缓存。因此,您通常希望将可变 header 的值归一化为一组已知的期望值。
在您的情况下,您想更改(并规范化) 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";
}
}
关于 Varnish 3 : Accept JSON returns HTML,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51628871/