我已经测试了您的 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,它将返回以下输出:
{"timestamp":"2021-11-24 07:38:35"}
否则返回以下纯输出:
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
这里有一些示例varnishlog 输出,用于 HTML 内容的现金未命中:
* << 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