使用Varnish 4,我有一组后端,它们使用有效的Content-Length
标头并且没有Transfer-Encoding
标头进行响应。
在客户端的第一次点击中,Varnish正在删除Content-Length
标头并将Transfer-Encoding: chunked
添加到响应中,而不是使用这些标头响应客户端。 (有趣的是,有效载荷似乎没有任何块 - 它是一个连续的有效载荷)。
这会给像Flash视频播放器这样的客户端造成严重问题,这些客户端正试图根据Content-Length
标头进行分段大小,带宽等分析。他们的分析失败了,他们不能做多比特流等等。
我尝试过一些半显而易见的事情:
beresp.do_stream = true
beresp.do_gzip = false
unset req.http.Accept-Encoding
示例后端响应:
HTTP/1.1 200 OK
Cache-Control: public, max-age=600
Content-Type: video/mp4
Date: Tue, 13 May 2014 19:44:35 GMT
Server: Apache
Content-Length: 796618
Connection: keep-alive
样品清漆响应:
HTTP/1.1 200 OK
Server: Apache
Cache-Control: public, max-age=600
Content-Type: video/mp4
Date: Tue, 13 May 2014 23:10:06 GMT
X-Varnish: 2
Age: 0
Transfer-Encoding: chunked
Accept-Ranges: bytes
对象的后续加载包括Content-Length
标题,而不是第一次加载到缓存中。
VCL:https://gist.github.com/onethumb/e64a405cc579909cace1
varnishlog输出:https://gist.github.com/onethumb/e66a2bc4727a3a5340b6
Varnish Trac:https://www.varnish-cache.org/trac/ticket/1506
答案 0 :(得分:6)
目前,do_stream = false
会做你想做的事。
在后端发送unchunked的情况下避免分块编码是Varnish未来可能的改进。
示例:
sub vcl_backend_response {
if(beresp.http.Content-Type ~ "video") {
set beresp.do_stream = false;
set beresp.do_gzip = false;
//set resp.http.Content-Length = beresp.http.Content-Length;
}
if(beresp.http.Edge-Control == "no-store") {
set beresp.uncacheable = true;
set beresp.ttl = 60s;
set beresp.http.Smug-Cacheable = "No";
return(deliver);
}
}
答案 1 :(得分:2)
因此解决方案根本不直观,但您必须启用esi处理:
sub vcl_backend_response {
set beresp.do_esi = true;
if(beresp.http.Content-Type ~ "video") {
set beresp.do_stream = true;
set beresp.do_gzip = false;
//set resp.http.Content-Length = beresp.http.Content-Length;
}
if(beresp.http.Edge-Control == "no-store") {
set beresp.uncacheable = true;
set beresp.ttl = 60s;
set beresp.http.Smug-Cacheable = "No";
return(deliver);
}
}
所以我通过浏览the source code发现了这一点。
特别是,Varnish这样做:
if (!req->disable_esi && req->obj->esidata != NULL) {
/* In ESI mode, we can't know the aggregate length */
req->res_mode &= ~RES_LEN;
req->res_mode |= RES_ESI;
}
上面的代码设置res_mode
标志。
过了一会儿:
if (!(req->res_mode & (RES_LEN|RES_CHUNKED|RES_EOF))) {
/* We havn't chosen yet, do so */
if (!req->wantbody) {
/* Nothing */
} else if (req->http->protover >= 11) {
req->res_mode |= RES_CHUNKED;
} else {
req->res_mode |= RES_EOF;
req->doclose = SC_TX_EOF;
}
}
如果HTTP协议为res_mode
或更高版本(在您的示例中为)并且res_mode标志不是RES_CHUNKED
标记设置为HTTP/1.1
设置
if (req->res_mode & RES_CHUNKED)
http_SetHeader(req->resp, "Transfer-Encoding: chunked");
如果设置了RES_CHUNKED
标志,则Varnish发送chuncked传输编码。
我认为有效禁用此功能的唯一方式是启用ESI模式。它会以其他一些方式被禁用,但这些方法并不实用(例如,对于HTTP HEAD请求或具有304状态代码的页面)。
答案 2 :(得分:1)
从清漆4.0升级到5.2,现在这也适用于第一个请求。