Varnish 升级后 HTML/JSON 接受无效
After Varnish Upgrade HTML/JSON Accept not working
在升级 varnish 4 -> varnish-6.2.1 后,“接受”请求未按预期响应。
如果我用“接受:application/json”发出第一个请求,它 returns HTML,在第二次请求时它会继续工作。
使用 Varnish3,遵循 Snippet 使其工作 - 但不适用于 varnish6
sub vcl_backend_response {
# Called after the response headers has been successfully retrieved from the backend.
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";
}
}
sub normalize {
# Normalize the header, remove the port (in case you're testing this on various TCP ports)
set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
# Remove the proxy header (see https://httpoxy.org/#mitigate-varnish)
unset req.http.proxy;
# Normalize the query arguments
set req.url = std.querysort(req.url);
if (req.http.Accept) {
if (req.http.Accept ~ "application/json") {
set req.http.Accept = "application/json";
} else {
set req.http.Accept = "text/html";
}
}
}
它不一样,但非常相似:
我已经测试了你的 VCL 代码,它工作正常。使 sub normalize
工作所需的唯一添加如下:
sub vcl_recv {
call normalize;
}
PHP测试脚本
我写了一个小测试脚本来复制原点的变化行为。这是代码:
<?php
header('Cache-Control: public, s-maxage=3600');
$timestamp = date('Y-m-d H:i:s');
if(isset($_SERVER['HTTP_ACCEPT']) && preg_match('/application\/json/',$_SERVER['HTTP_ACCEPT'])) {
header('Content-Type: application/json');
$obj = new stdClass;
$obj->timestamp = $timestamp;
echo json_encode($obj);
} else {
echo $timestamp;
}
如果在Accept
中找到application/json
header它returns输出如下:
{"timestamp":"2021-11-24 07:38:35"}
否则它returns下面的纯输出:
2021-11-24 07:38:35
VCL
这是我为此使用的 VCL:
vcl 4.1;
import std;
backend default {
.host = "localhost";
.port = "8080";
}
sub vcl_backend_response {
# Called after the response headers has been successfully retrieved from the backend.
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";
}
}
sub normalize {
# Normalize the header, remove the port (in case you're testing this on various TCP ports)
set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
# Remove the proxy header (see https://httpoxy.org/#mitigate-varnish)
unset req.http.proxy;
# Normalize the query arguments
set req.url = std.querysort(req.url);
if (req.http.Accept) {
if (req.http.Accept ~ "application/json") {
set req.http.Accept = "application/json";
} else {
set req.http.Accept = "text/html";
}
}
}
sub vcl_recv {
call normalize;
}
如果这对您不起作用,如何调试?
您可以运行以下varnishlog
命令来查看发生了什么:
varnishlog -g request -I ReqHeader:Accept -i requrl -i berequrl -I RespHeader:Vary -I BereqHeader:Accept -I BerespHeader:Vary -i vcl_call -i vcl_return
这是 HTML 内容 现金未命中 的一些示例 varnishlog
输出:
* << Request >> 34
- ReqURL /test
- ReqHeader Accept: */*
- VCL_call RECV
- ReqURL /test
- ReqHeader Accept: text/html
- VCL_return hash
- VCL_call HASH
- VCL_return lookup
- VCL_call MISS
- VCL_return fetch
- RespHeader Vary: Accept
- VCL_call DELIVER
- VCL_return deliver
** << BeReq >> 35
-- BereqURL /test
-- BereqHeader Accept: text/html
-- BereqHeader Accept-Encoding: gzip
-- VCL_call BACKEND_FETCH
-- VCL_return fetch
-- VCL_call BACKEND_RESPONSE
-- BerespHeader Vary: Accept
-- VCL_return deliver
这是常规 HTML 的 缓存命中 发生的情况:
* << Request >> 32800
- ReqURL /test
- ReqHeader Accept: */*
- VCL_call RECV
- ReqURL /test
- ReqHeader Accept: text/html
- VCL_return hash
- VCL_call HASH
- VCL_return lookup
- VCL_call HIT
- VCL_return deliver
- RespHeader Vary: Accept
- VCL_call DELIVER
- VCL_return deliver
即使 HTML 版本仍在缓存中,Accept: application/json
也会导致缓存未命中:
* << Request >> 32802
- ReqURL /test
- ReqHeader Accept:application/json
- VCL_call RECV
- ReqURL /test
- ReqHeader Accept: application/json
- VCL_return hash
- VCL_call HASH
- VCL_return lookup
- VCL_call MISS
- VCL_return fetch
- RespHeader Vary: Accept
- VCL_call DELIVER
- VCL_return deliver
** << BeReq >> 32803
-- BereqURL /test
-- BereqHeader Accept: application/json
-- BereqHeader Accept-Encoding: gzip
-- VCL_call BACKEND_FETCH
-- VCL_return fetch
-- VCL_call BACKEND_RESPONSE
-- BerespHeader Vary: Accept
-- VCL_return deliver
下一次,这将导致 JSON 输出命中:
* << Request >> 32805
- ReqURL /test
- ReqHeader Accept:application/json
- VCL_call RECV
- ReqURL /test
- ReqHeader Accept: application/json
- VCL_return hash
- VCL_call HASH
- VCL_return lookup
- VCL_call HIT
- VCL_return deliver
- RespHeader Vary: Accept
- VCL_call DELIVER
- VCL_return deliver
在升级 varnish 4 -> varnish-6.2.1 后,“接受”请求未按预期响应。
如果我用“接受:application/json”发出第一个请求,它 returns HTML,在第二次请求时它会继续工作。
使用 Varnish3,遵循 Snippet 使其工作 - 但不适用于 varnish6
sub vcl_backend_response {
# Called after the response headers has been successfully retrieved from the backend.
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";
}
}
sub normalize {
# Normalize the header, remove the port (in case you're testing this on various TCP ports)
set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
# Remove the proxy header (see https://httpoxy.org/#mitigate-varnish)
unset req.http.proxy;
# Normalize the query arguments
set req.url = std.querysort(req.url);
if (req.http.Accept) {
if (req.http.Accept ~ "application/json") {
set req.http.Accept = "application/json";
} else {
set req.http.Accept = "text/html";
}
}
}
它不一样,但非常相似:
我已经测试了你的 VCL 代码,它工作正常。使 sub normalize
工作所需的唯一添加如下:
sub vcl_recv {
call normalize;
}
PHP测试脚本
我写了一个小测试脚本来复制原点的变化行为。这是代码:
<?php
header('Cache-Control: public, s-maxage=3600');
$timestamp = date('Y-m-d H:i:s');
if(isset($_SERVER['HTTP_ACCEPT']) && preg_match('/application\/json/',$_SERVER['HTTP_ACCEPT'])) {
header('Content-Type: application/json');
$obj = new stdClass;
$obj->timestamp = $timestamp;
echo json_encode($obj);
} else {
echo $timestamp;
}
如果在Accept
中找到application/json
header它returns输出如下:
{"timestamp":"2021-11-24 07:38:35"}
否则它returns下面的纯输出:
2021-11-24 07:38:35
VCL
这是我为此使用的 VCL:
vcl 4.1;
import std;
backend default {
.host = "localhost";
.port = "8080";
}
sub vcl_backend_response {
# Called after the response headers has been successfully retrieved from the backend.
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";
}
}
sub normalize {
# Normalize the header, remove the port (in case you're testing this on various TCP ports)
set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
# Remove the proxy header (see https://httpoxy.org/#mitigate-varnish)
unset req.http.proxy;
# Normalize the query arguments
set req.url = std.querysort(req.url);
if (req.http.Accept) {
if (req.http.Accept ~ "application/json") {
set req.http.Accept = "application/json";
} else {
set req.http.Accept = "text/html";
}
}
}
sub vcl_recv {
call normalize;
}
如果这对您不起作用,如何调试?
您可以运行以下varnishlog
命令来查看发生了什么:
varnishlog -g request -I ReqHeader:Accept -i requrl -i berequrl -I RespHeader:Vary -I BereqHeader:Accept -I BerespHeader:Vary -i vcl_call -i vcl_return
这是 HTML 内容 现金未命中 的一些示例 varnishlog
输出:
* << Request >> 34
- ReqURL /test
- ReqHeader Accept: */*
- VCL_call RECV
- ReqURL /test
- ReqHeader Accept: text/html
- VCL_return hash
- VCL_call HASH
- VCL_return lookup
- VCL_call MISS
- VCL_return fetch
- RespHeader Vary: Accept
- VCL_call DELIVER
- VCL_return deliver
** << BeReq >> 35
-- BereqURL /test
-- BereqHeader Accept: text/html
-- BereqHeader Accept-Encoding: gzip
-- VCL_call BACKEND_FETCH
-- VCL_return fetch
-- VCL_call BACKEND_RESPONSE
-- BerespHeader Vary: Accept
-- VCL_return deliver
这是常规 HTML 的 缓存命中 发生的情况:
* << Request >> 32800
- ReqURL /test
- ReqHeader Accept: */*
- VCL_call RECV
- ReqURL /test
- ReqHeader Accept: text/html
- VCL_return hash
- VCL_call HASH
- VCL_return lookup
- VCL_call HIT
- VCL_return deliver
- RespHeader Vary: Accept
- VCL_call DELIVER
- VCL_return deliver
即使 HTML 版本仍在缓存中,Accept: application/json
也会导致缓存未命中:
* << Request >> 32802
- ReqURL /test
- ReqHeader Accept:application/json
- VCL_call RECV
- ReqURL /test
- ReqHeader Accept: application/json
- VCL_return hash
- VCL_call HASH
- VCL_return lookup
- VCL_call MISS
- VCL_return fetch
- RespHeader Vary: Accept
- VCL_call DELIVER
- VCL_return deliver
** << BeReq >> 32803
-- BereqURL /test
-- BereqHeader Accept: application/json
-- BereqHeader Accept-Encoding: gzip
-- VCL_call BACKEND_FETCH
-- VCL_return fetch
-- VCL_call BACKEND_RESPONSE
-- BerespHeader Vary: Accept
-- VCL_return deliver
下一次,这将导致 JSON 输出命中:
* << Request >> 32805
- ReqURL /test
- ReqHeader Accept:application/json
- VCL_call RECV
- ReqURL /test
- ReqHeader Accept: application/json
- VCL_return hash
- VCL_call HASH
- VCL_return lookup
- VCL_call HIT
- VCL_return deliver
- RespHeader Vary: Accept
- VCL_call DELIVER
- VCL_return deliver