清漆中的 ESI 不像浏览器中的 iframe 或链接标签那样工作,因为它不会连接到您提供的任何 url。ESI 只是在 varnish 中启动一个新请求并通过工作流(vcl_recv 等)。
您期望 varnish 像 http 客户端一样工作,解析 url,设置授权标头,将主机标头设置为 api.dev:8081 并启动新的 http 连接/请求,但它不会。在这种情况下,我的猜测是它会启动一个新的 req,其中 req.url 设置为 /app.php/next 继承父资源请求的标头(包含 esi 标签),或者可能只是完全忽略 esi 标签。
完成您想做的事情的方法是(在 vcl_recv 中):
if (req.esi_level > 0 && req.url == "/app.php/next") {
set req.http.Authorization = "BASIC [base64 encoded admin:adminpass]"
return (pass);
}
然后esi标签应该看起来像<esi:include src="/app.php/next" />
如果您需要 ESI 请求访问不同的后端服务器,则需要将该服务器添加为不同的命名后端:
backend authorization_needed {
.host = "api.dev";
.port = "8081";
}
并在 vcl_recv 中,告诉 varnish 将其用于 esi 请求:
if (req.esi_level > 0 && req.url == "/app.php/next") {
set req.http.Authorization = "BASIC [base64 encoded admin:adminpass]"
set req.backend = authorization_needed;
return (pass);
}
如果后端响应与“api.dev”不同的虚拟主机,您可能还需要在 if 块中设置 req.http.Host。
更新:
由于基本授权来自客户端,并且当 req.http.Authorization 存在时您正在调用 return(pass),varnish 不会 ESI 处理这些页面。您必须在通过时不调用的 vcl_fetch() 中显式启用 esi。
因此,要通过 ESI 片段而不是父页面的授权,请更改 vcl_rev:
if (req.http.Authorization && req.esi_level == 0) {
set req.http.X-Esi-Authorization = req.http.Authorization;
unset req.http.Authorization;
}
else if (req.http.X-Esi-Authorization && req.esi_level > 0 ) {
set req.http.Authorization = req.http.X-Esi-Authorization;
return (pass);
}
并添加到 vcl_fetch:
if (req.http.X-Esi-Authorization) {
set beresp.do_esi = true;
}
最终效果是父响应是可缓存的并且将处理 esi,esi 片段本身将始终与客户端的授权标头一起传递给后端。