我们使用 Symfony (Sulu) 和 Varnish 作为反向代理,基于标签的失效 (xkey) 可以按预期工作。现在我们希望将 ESI 用于我们网站上的动态块,与“主”缓存生命周期分开。
但是每次网页被完全缓存时,即使在硬刷新/清除浏览器缓存或使用新浏览器之后,页面始终显示第一个缓存条目。
我们已在 Symfony 中启用 ESI:
framework:
...
esi: true
fragments: { path: /_fragment }
并在我们的 Twig 模板中提供 render_esi:
navbar.html.twig
...
{{ render_esi(controller('App\\Controller\\Website\\LoginButtonController::renderEsiLoginButton')) }}
<div class="navbar-main__toggler"></div>
</div>
LoginButtonController
class LoginButtonController extends AbstractController
{
public function renderEsiLoginButton(): Response
{
$response = $this->render('esi/_login_button.html.twig', ['random_nr' => rand()]);
$response->setMaxAge(10);
$response->setSharedMaxAge(10);
$response->setPublic();
return $response;
}
}
_login_button.html.twig
<div class="navbar-main__action-account">
<div class="account__dropdown">
<a href="#" class="account__user">{{ random_nr }}</a>
...
</div>
</div>
还有我们的 Varnish default.vcl:
sub vcl_recv {
call fos_tags_xkey_recv;
call fos_user_context_recv;
call sulu_recv;
// # Add a Surrogate-Capability header to announce ESI
set req.http.Surrogate-Capability = "abc=ESI/1.0";
...
sub vcl_backend_response {
set beresp.grace = 2m;
call fos_user_context_backend_response;
call sulu_backend_response;
// Check for ESI acknowledgement and remove Surrogate-Control header
if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
unset beresp.http.Surrogate-Control;
set beresp.do_esi = true;
}
}
...
我们的 fos_http_cache 配置:
fos_http_cache:
tags:
enabled: true
response_header: xkey
max_header_value_length: 1024
proxy_client:
symfony:
use_kernel_dispatcher: true
user_context:
enabled: true
role_provider: true
# user_hash_header: 'X-User-Context-Hash'
hash_cache_ttl: 900
和sulu http缓存:
when@prod: &prod
sulu_http_cache:
debug:
enabled: false
tags:
enabled: true
cache:
max_age: 240
shared_max_age: 480
proxy_client:
symfony:
enabled: false
varnish:
enabled: true
servers: [ '%env(VARNISH_SERVER)%' ]
tag_mode: purgekeys
使用curl时,我们也可以正确看到esi:include标签:
<span class="navbar-main__action-search-button"></span>
<esi:include src="/_fragment?_hash=HAz3Ym5wXab4GXTRKnq8oUR3WwnGqUpprL0niBc%2BEwg%3D&_path=_format%3Dhtml%26_locale%3Den%26_controller%3DApp%255CController%255CWebsite%255CLoginButtonController%253A%253ArenderEsiLoginButton" onerror="continue" />
<div class="navbar-main__toggler"></div>
但是网页仍然被完整缓存,即使在硬刷新/清除浏览器缓存或使用新浏览器之后,页面始终显示第一个随机数。直到我们完全清除 Varnish 缓存。
我们还缺少什么?
从表面上看,你做的一切都是正确的。但是一些有针对性的
varnishlog
命令将使我们更好地了解 Varnish 如何缓存各种片段。
我需要您向我发送以下命令的输出:
sudo varnishlog -g request -q "ReqUrl eq '/'"
我的假设是问题发生在主页上。如果情况并非如此,请更改
varnishlog
命令中的过滤器。
在空缓存上运行此命令非常重要!
当 Varnish 执行各种获取时,我们可以查看日志中的
TTL
标签。这将告诉我们 Varnish 如何决定每个片段的 TTL(通过 VCL 代码中设置的 TTL,或通过 Cache-Control
标头。
日志还会将各种 ESI 子请求作为单独的日志事务返回,从而更容易了解何时发生的情况。
请将日志输出放在您原来的问题中,我将帮助您弄清楚发生了什么。