web-dev-qa-db-ja.com

Varnishで「Transfer-Encoding:chunked」エンコーディングを無効にするにはどうすればよいですか?

Varnish 4 を使用すると、有効なContent-Lengthヘッダーで応答しているバックエンドのセットがあります。Transfer-Encodingヘッダーはありません。

クライアントからの最初のヒットで、Varnishはこれらのヘッダーでクライアントに応答するのではなく、Content-Lengthヘッダーを削除し、応答にTransfer-Encoding: chunkedを追加します。 (興味深いことに、ペイロードにはチャンクが含まれていないようです。これは1つの連続したペイロードです)。

これは、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

12
Don MacAskill

当面、 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);
        }
}
6
Nils Goroll

したがって、ソリューションはまったく直感的ではありませんが、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);
        }
}

だから私はこれを閲覧して発見しました ソースコード

特に、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に設定されます。 t set。今でも後で:

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

RES_CHUNKEDフラグが設定されている場合、Varnishはチャンク転送エンコーディングを送信します。

これを効果的に無効にするために私が見るonlyの方法は、ESIモードを有効にすることです。他のいくつかの方法で無効になります、ただし、これらは実用的ではありません(たとえば、HTTP HEADリクエストまたは304ステータスコードのページ)。

2

ワニス4.0から5.2にアップグレードされ、これは最初のリクエストでも正しく機能するようになりました。

1
Piotr Jankowski