【问题标题】:How do I disable 'Transfer-Encoding: chunked' encoding in Varnish?如何在 Varnish 中禁用“传输编码:分块”编码?
【发布时间】:2014-07-01 20:01:36
【问题描述】:

使用Varnish 4,我有一组后端以有效的Content-Length 标头响应,而没有Transfer-Encoding 标头。

在客户端第一次点击时,Varnish 不会使用这些标头响应客户端,而是删除Content-Length 标头并将Transfer-Encoding: chunked 添加到响应中。 (有趣的是,有效载荷中似乎没有任何块 - 它是一个连续的有效载荷)。

这会给尝试基于 Content-Length 标头进行分段大小、带宽等分析的 Flash 视频播放器等客户端带来严重问题。他们的分析失败了,他们不能做多比特率流等事情。

我尝试了一些半显而易见的事情,例如:

  • 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

对象的后续加载 do 包括 Content-Length 标头,而不是第一次加载到缓存中。

VCL:https://gist.github.com/onethumb/e64a405cc579909cace1

varnishlog 输出:https://gist.github.com/onethumb/e66a2bc4727a3a5340b6

清漆跟踪:https://www.varnish-cache.org/trac/ticket/1506

【问题讨论】:

  • 也有这个问题,等待更新不要绕过流光。

标签: http varnish chunked transfer-encoding http-content-length


【解决方案1】:

目前,do_stream = false 会为所欲为。

在后端发送未分块的情况下避免分块编码是 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);
        }
}

【讨论】:

  • 删除了我的答案,你的更好
  • 我已经尝试过set beresp.do_stream=false,结果相同。 :(
  • 我应该澄清一下,现在我已经做了更多的测试。 beresp.do_stream=false 提高了成功率,但仍然会出现错误。即使将do_stream 设置为false,我也至少能解决这个问题的 10%
  • @BrandonWamoldt 您的回答很棒,因为它巧妙地指出了可能对新手有帮助的相关代码(他们可能缺乏查看答案所需的声誉)。谢谢,无论如何+1在这里=)
  • @DonMacAskill 只是好奇,尝试根据我的回答启用 ESI,看看是否可行。我得到 100% 的成功率。
【解决方案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;
    }
}

这会将res_mode 标志设置为RES_CHUNKED,如果HTTP 协议是HTTP/1.1 或更高版本(在您的示例中)并且未设置 res_mode 标志。现在甚至更晚:

if (req->res_mode & RES_CHUNKED)
    http_SetHeader(req->resp, "Transfer-Encoding: chunked");

如果设置了RES_CHUNKED 标志,Varnish 会发送分块传输编码。

我认为有效禁用此功能的唯一方法是启用 ESI 模式。它通过其他几种方式被禁用,但这些方式不实用(例如,对于 HTTP HEAD 请求或具有 304 状态代码的页面)。

【讨论】:

  • if (!(req->res_mode & (RES_LEN|RES_CHUNKED|RES_EOF))) 检查res_mode 标志是否设置了RES_LENRES_CHUNKEDRES_EOF,但if (!req->disable_esi && req->obj->esidata != NULL) 中的代码仅取消设置RES_LEN 并设置RES_ESI。而根据hereContent-Length最终会被剥离吗?
【解决方案3】:

从 varnish 4.0 升级到 5.2,现在这也适用于第一个请求。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-12
    • 2023-03-16
    • 1970-01-01
    • 2015-12-11
    • 1970-01-01
    • 2015-06-15
    相关资源
    最近更新 更多