web-dev-qa-db-ja.com

Content-Lengthヘッダーとチャンクエンコーディング

私は、Content-Length HTTPヘッダーを設定することと、チャンクエンコーディングを使用して[おそらく]サーバーから大きなファイルを返すことの長所と短所を比較検討しています。永続的な接続を使用してHTTP 1.1仕様に準拠するには、どちらか一方が必要です。 Content-Lengthヘッダーの利点は次のとおりです。

  • ダウンロードダイアログで正確な進行状況バーを表示できる
  • クライアントは、ファイルが大きすぎて取り込めないかどうかを事前に認識します。

欠点は、オブジェクトを返す前にサイズを計算する必要があることです。これは、常に実用的であるとは限らず、サーバー/データベースの使用率を増加させる可能性があります。チャンクエンコーディングの欠点は、各チャンクとダウンロードプログレスバーの前にチャンクサイズを追加することによる小さなオーバーヘッドです。何かご意見は?私が考えていなかったかもしれない他のHTTPに関する考慮事項

35
Gandalf

確かにContent-Lengthを使用してください。これによるサーバーの使用率はほとんどなくなり、ユーザーにとってのメリットは大きくなります。

動的コンテンツの場合、圧縮応答サポート(gzip)を追加することも非常に簡単です。これには出力バッファリングが必要であり、これによりコンテンツの長さが得られます。 (ファイルのダウンロードや既に圧縮されたコンテンツ(サウンド、画像)では実用的ではありません)。

部分的なコンテンツ/バイト範囲の提供、つまりダウンロードを再開する機能のサポートを追加することも検討してください。 バイト範囲の例についてはこちらを参照 (例はPHPにありますが、任意の言語に適用できます)。部分的なコンテンツを提供する場合はContent-Lengthが必要です。

もちろん、これらは特効薬ではありません。ストリーミングメディアの場合、出力バッファリングや応答サイズを使用しても意味がありません。大きなファイルの場合、出力バッファリングは意味がありませんが、Content-Lengthとバイトサービングは非常に意味があります(失敗したダウンロードの再開が可能です)。

個人的に、私はそれを知っているときはいつでもContent-Lengthを提供します。ファイルのダウンロードの場合、ファイルサイズの確認はリソースの点では重要ではありません。結果:ユーザーには確定的な進行状況バーがあります(gzipのおかげで動的ページのダウンロードが速くなります)。

コンテンツの長さが事前にわかっている場合は、チャンクで送信するよりも確実に優先します。ローカルディスクファイルシステムまたはデータベースに静的ファイルの手段がある場合、自尊心のあるプログラミング言語とRDBMSは、コンテンツの長さを事前に取得する方法を提供します。あなたはそれを利用するべきです。

一方、コンテンツの長さが事前に本当に予測不可能である場合(たとえば、いくつかのファイルをまとめてZipして1つとして送信する場合)、サーバーのメモリにバッファリングしたり、ローカルディスクに書き込んだりするよりも、チャンクで送信する方が速い場合があります。最初にファイルシステム。ただし、ダウンロードの進行状況が不明であるため、これは実際にユーザーエクスペリエンスに悪影響を及ぼします。せっかちな人はダウンロードを中止して先に進むかもしれません。

コンテンツの長さを事前に知ることのもう1つの利点は、ダウンロードを再開できることです。あなたの投稿履歴で、主なプログラミング言語はJavaであることがわかりました。あなたは here より技術的な背景情報とJavaそれを行うサーブレットの例を含む記事を見つけることができます。

12
BalusC

Content-Length

Content-Lengthヘッダーは、リクエスト/レスポンス本文のバイト長を決定します。 Content-Lengthヘッダーを指定しなかった場合、HTTPサーバーは暗黙的にTransfer-Encoding: chunkedヘッダーを追加します。 Content-LengthヘッダーとTransfer-Encodingヘッダーを一緒に使用しないでください。受信者はボディの長さがわからないため、ダウンロード完了時間を予測できません。 Content-Lengthヘッダーを追加する場合は、本文全体がバイト単位で一致することを確認してください。正しくない場合、レシーバーの動作は未定義です。

Content-Lengthヘッダーはストリーミングを許可しませんが、部分的なコンテンツサービスをサポートする必要がある大きなバイナリファイルに役立ちます。これは基本的に、再開可能なダウンロード、一時停止したダウンロード、部分的なダウンロード、マルチホームダウンロードを意味します。これには、Rangeという追加のヘッダーを使用する必要があります。この手法は Byte serve と呼ばれます。

Transfer-Encoding

Transfer-Encoding: chunkedの使用により、単一の要求または応答内でのストリーミングが可能になります。つまり、データはチャンク形式で送信され、コンテンツの表現には影響しません。

正式には、HTTPクライアントは、クライアントが受け入れようとしている転送エンコーディングの種類を指定するTEヘッダーフィールドを含むリクエストを送信することを意図しています。これは常に送信されるわけではありませんが、ほとんどのサーバーはクライアントがchunkedエンコーディングを処理できると想定しています。

chunked転送エンコーディングは、永続的なTCP接続をより適切に使用します。HTTP1.1はデフォルトでtrueであると想定しています。

Content-Encoding

チャンクされたデータまたはチャンクされていないデータを圧縮することもできます。これは実際にはContent-Encodingヘッダーを介して行われます。

Content-Lengthは、Content-Encodingの後の本文の長さに等しいことに注意してください。つまり、応答をgzip圧縮した場合、圧縮後に長さの計算が行われます。長さを計算する場合は、ボディ全体をメモリにロードできる必要があります(他にその情報がない場合)。

チャンクエンコーディングを使用してストリーミングする場合、圧縮アルゴリズムはオンライン処理もサポートする必要があります。ありがたいことに、gzipはストリーム圧縮をサポートしています。コンテンツは最初に圧縮され、次にチャンクに切り分けられると思います。このようにして、チャンクが受信され、解凍されて実際のコンテンツが取得されます。逆の場合は、圧縮されたストリームを取得し、解凍するとチャンクが得られます。これは意味がありません。

一般的な圧縮ストリーム応答には、次のヘッダーがあります。

Content-Type: text/html
Content-Encoding: gzip
Transfer-Encoding: chunked

意味的には、Content-Encodingの使用は「エンドツーエンド」のエンコーディングスキームを示します。つまり、最終的なクライアントまたは最終的なサーバーのみがコンテンツをデコードすることになります。真ん中のプロキシはコンテンツをデコードすることを想定していません。

途中のプロキシにコンテンツのデコードを許可する場合、実際に使用する正しいヘッダーはTransfer-Encodingヘッダーです。 HTTPリクエストがTE: gzip chunkedヘッダーを所有していた場合、Transfer-Encoding: gzip chunkedで応答することは正当です。

ただし、これがサポートされることはほとんどありません。したがって、現時点では、圧縮にはContent-Encodingのみを使用する必要があります。

チャンクvsストア&フォワード

5
Dhairya Lakhera