Varnish 可以通过将不同的页面(称为片段)组合成一个页面来创建网页。这些片段可以有各自的缓存策略。如果您的网站上有一个列表,显示网站上最受欢迎的五篇文章,那么这个列表就可以作为一个片段缓存,并包含在所有其他页面中。
如果使用得当,这一策略可以显著提高命中率,减少服务器的负荷。
在 Varnish 中,我们只实现了 ESI 的一小部分,因为其余大部分 ESI 规范设施都可以通过 VCL 更简单、更好地完成:
esi:include
esi:remove
<!--esi ...-->
未实现基于变量和 cookie 的内容替换。
Varnish 不会处理 HTML 注释中的 ESI 指令。
6.1 示例:esi:include
让我们来看一个如何使用的示例。这个简单的 cgi 脚本输出日期:
#!/bin/sh
echo 'Content-type: text/html'
echo ''
date "+%Y-%m-%d %H:%M"
现在,让我们来看一个包含 ESI 包含语句的 HTML 文件:
<HTML>
<BODY>
The time is: <esi:include src="/cgi-bin/date.cgi"/>
at this very moment.
</BODY>
</HTML>
要使 ESI 正常工作,您需要在 VCL 中激活 ESI 处理,就像这样:
sub vcl_backend_response {
if (bereq.url == "/test.html") {
set beresp.do_esi = true; // Do ESI processing
set beresp.ttl = 24 h; // Sets the TTL on the HTML above
} elseif (bereq.url == "/cgi-bin/date.cgi") {
set beresp.ttl = 1m; // Sets a one minute TTL on
// the included object
}
}
请注意,对于包含的片段,除非也包含 <ESI::include …/> 指令,否则不需要设置 beresp.do_esi = true; 也应避免这样做。
6.2 示例:esi:remove 和 <!–esi … –>
esi:remove和<!-esi …->结构可用于在ESI可用与否的情况下呈现适当的内容,例如,您可以在ESI可用时包含内容,或在ESI不可用时链接到内容。在处理页面时,ESI 处理器会移除起始(“<!-esi”)和结束(“->”),但仍会处理内容。如果页面未被处理,它将保持不变,成为 HTML/XML 注释标记。ESI 处理器会移除 esi:remove 标记和其中包含的所有内容,这样就可以只在不对页面进行 ESI 处理时呈现内容。例如:
<esi:remove>
<a href="http://www.example.com/LICENSE">The license</a>
</esi:remove>
<!--esi
<p>The full text of the license:</p>
<esi:include src="http://example.com/LICENSE" />
-->
6.3 失败时会发生什么?
默认情况下,片段必须有resp.status
200 或 206,否则包含它们将导致父请求中止。
同样,如果片段是流式获取,且获取失败,父请求也会中止。
如果包含合成片段,即在 vcl_backend_error{}
或中创建的片段vcl_synth{}
,则必须 (be)resp.status
在之前设置为 200return(deliver);
我们说“中止”而不是“失败”,因为当 Varnish 开始插入片段时,HTTP 响应头早已发送完毕,并且不再可能将父请求更改为 5xx,所以唯一的resp.status
方法表示有问题的信号是关闭连接。但是,可以<ESI:include…
通过设置来允许个人在失败时继续:
param.set feature +esi_include_onerror
并标记这些具体内容包括:
<ESI:include src="…" οnerrοr="continue"/>
6.4 ESI 片段也可以使用 ESI-includes 吗?
是的,但是深度受max_esi_depth
参数限制,以防止无限递归。
6.5 对 JSON 和其他非 XML 内容执行 ESI
Varnish 会查看对象的第一个字节,如果它不是“<”,Varnish 会假设您并不是真的想让 ESI 处理它。您可以通过以下方式禁用此检查:
param.set feature +esi_disable_xml_check
6.6 忽略 ESI 对象中的 BOM
如果后端输出 Unicode 字节顺序标记作为响应的第一个字节,则“<”检查将失败,除非您设置:
param.set feature +esi_remove_bom
6.7 无效 XML 上的 ESI
ESI 解析器期望 XML 的格式相当良好,但如果您是包含非 XML 文件的 ESI,则这可能会失败。您可以通过设置使 ESI 解析器忽略除 ESI 标记之外的任何内容:
param.set feature +esi_ignore_other_elements
6.8 ESI 包含 HTTPS 协议
如果ESI:include标签指定了HTTPS协议,默认情况下它将被忽略,因为Varnish无法通过加密来获取它。如果您希望 Varnish 像执行其他操作一样获取它们,请设置:
param.set feature +esi_ignore_https
6.9 部分响应的 ESI (206)
Varnish 支持范围请求,但一般来说,部分响应在 ESI 上下文中没有意义。
如果您确实知道自己在做什么,请将 206 更改为 200:
sub vcl_backend_response {
if (beresp.status == 206 && beresp.http.secret == "swordfish") {
set beresp.do_esi = True;
set beresp.status = 200;
}
}
6.10 ESI 和返回(vcl(…))
如果原始客户端请求使用 return(vcl(...))
in切换到不同的 VCL vcl_recv
,则任何 esi:include-requests 仍将在与原始请求相同的 VCL 中开始,而不是 在它切换到的 VCL 中开始。
6.11 ESI 和 gzip 压缩
Varnish 的 ESI 实现会自动处理 gzip 压缩,无论它如何混合:父请求可以压缩或解压缩,片段也可以压缩或解压缩,这一切都可以解决。
Varnish 会分别压缩 ESI 响应的所有部分,并在交付过程中将它们动态拼接在一起,这会对压缩比产生负面影响。
当您使用 gzip 压缩响应时,它将在获取过程中被解压缩并部分重新压缩。set beresp.do_esi = True;
部分压缩减少了删除冗余的机会,因为 gzip 数据流中的反向引用不能指向它自己的部分之外。
另一种影响压缩率的情况是,如果将未压缩的片段插入到压缩的响应中。