web-dev-qa-db-ja.com

Apacheでgzip圧縮を有効にするとContent-Lengthが送信されませんか?

このApacheの振る舞いを理解する手助けをしていただければ幸いです。

PHP application/jsonのiPhone Objective-Cアプリから)と通信しています。サーバーでGzip圧縮が有効になっていて、クライアントからリクエストされています。

私の.htaccessから:

AddOutputFilterByType DEFLATE text/html text/plain text/xml application/x-httpd-php application/json

小さなリクエストの場合、Apacheは 'Content-Length'ヘッダーを設定しています。例(これらの値は、ヘッダーからObjective-Cに出力されます):

Connection = "Keep-Alive";
"Content-Encoding" = gzip;
"Content-Length" = 185;     <-------------
"Content-Type" = "application/json";
Date = "Wed, 22 Sep 2010 12:20:27 GMT";
"Keep-Alive" = "timeout=3, max=149";
Server = Apache;
Vary = "Accept-Encoding";
"X-Powered-By" = "PHP/5.2.13";
"X-Uncompressed-Content-Length" = 217;

X-Uncompressed-Content-Lengthは、非圧縮のJSON文字列のサイズにセットを追加するヘッダーです。

ご覧のとおり、このリクエストは非常に小さくなっています(217バイト)。

これは、大きなリクエスト(282888バイト)のヘッダーです。

Connection = "Keep-Alive";
"Content-Encoding" = gzip;
"Content-Type" = "application/json";
Date = "Wed, 22 Sep 2010 12:20:29 GMT";
"Keep-Alive" = "timeout=3, max=148";
Server = Apache;
"Transfer-Encoding" = Identity;
Vary = "Accept-Encoding";
"X-Powered-By" = "PHP/5.2.13";
"X-Uncompressed-Content-Length" = 282888;

Content-Lengthが指定されていないことに注意してください。

私の質問:

  1. Apacheがより大きなリクエストに対してContent-Lengthを送信しないのはなぜですか?
  2. 'Contend-Encoding = gzip'が設定されているという事実は、サイズの違いを確認できない場合でも、gzip圧縮がより大きなリクエストで引き続き機能していることを意味しますか?
  3. Apacheにこれらの大きなリクエストの実際のContent-Lengthを含めて、ユーザーにデータ使用量をより正確に報告する方法はありますか?

このアプリは高額なデータプランで使用できるため、ユーザーに実際の使用状況を報告したいのですが、30〜70%の使用量を膨らませることはありません(数百KBの追加はそれほど聞こえないかもしれませんが、これらのプランの費用は$ 1からMBあたり$ 10!)。

前もって感謝します。

13
William Denniss

Martin Fjordvaldsの回答への追加:

Apacheは、圧縮ファイルのサイズがDeflateBufferSizeより大きい場合にのみ、チャンクエンコーディングを使用します。したがって、このバッファーサイズを増やすと、サーバーが大きなファイルにもチャンクエンコーディングを使用できなくなり、zip形式のデータでもContent-Lengthが送信されます。

詳細については、こちらをご覧ください: http://httpd.Apache.org/docs/2.2/mod/mod_deflate.html#deflatebuffersize

14
Philippe

Apacheはチャンクエンコーディングを行っているように聞こえます。つまり、完全な応答がgzipされるのを待つのではなく、gzipされているデータを送信できます。これはかなり標準的な方法ですが、Apacheを無効にできるかどうかについては十分に理解していません。

7

はい、なんとか解決しました。 Martin Fが正しく指摘しているように、Apacheは応答をチャンクしているため、コンテンツのサイズは不明です。これは多くの人にとって望ましいことです(ページの読み込みが速くなります)。これには、ダウンロードの進行状況を報告できないという代償が伴います。

私のように本当にダウンロードの進行状況を報告したい人にとって、ApacheまたはPHPの自動gzipサポートを使用している場合、できることはほとんどありません。解決策は手動で行うことです。思ったより簡単です。

ファイル全体を送信する場合、これはPHPでの1つのチャンクを(Content-Lengthで)強制するための素晴らしい例です。 http://www.php。 net/manual/en/function.ob-start.php#94741

生成されたデータを送信する場合は、上記のサンプルのように、gzencodeを使用してデータをエンコードします。前提条件は、すべての出力データが変数に格納されていることです(バッファする必要がある場合は、ob_startを使用してこれを支援できます。次に、バッファのコンテンツを取得します)。

        // $replyBody is the entire contents of your reply

        header("Content-Type: application/json");  // or whatever yours is

        // checks if gzip is supported by client
        $pack = true;
        if(empty($_SERVER["HTTP_ACCEPT_ENCODING"]) || strpos($_SERVER["HTTP_ACCEPT_ENCODING"], 'gzip') === false)
        {
            $pack = false;
        }

        // if supported, gzips data
        if($pack) {
            header("Content-Encoding: gzip");
            $replyBody = gzencode($replyBody, 9, FORCE_GZIP);
        }

        // compressed or not, sets the Content-Length           
        header("Content-Length: " . mb_strlen($replyBody, 'latin1'));

        // outputs reply & exits
        echo $replyBody;
        exit;

そして出来上がり!

自分で行うもう1つの大きな利点は、圧縮レベルを設定できることです。最高の圧縮レベルに設定できるので、これは私のモバイルアプリケーションに最適です(ユーザーがデータに支払う費用が少なくて済みます!)。一方、サーバーは、中程度の圧縮レベルのみを使用して、CPUとサイズのトレードオフを改善します。圧縮レベルは、httpd.conf(共有ホスティングではできません)を編集できる場合にのみ変更できると思います。

ですから、DEFLATE .htaccessディレクティブはすべて残しておきますが、私のapplication/json応答は、上記の方法でエンコードします。

マーティンFにもう一度感謝します。sparkこれを解決する必要がありました:)

5
William Denniss