Content-Length
使い方
Content-Length ヘッダーは、HTTP メッセージボディの正確なバイトサイズを伝えます。クライアントはこの値を頼りにレスポンスを完全に受信し終えたことを把握し、HTTP/1.1 の持続的接続で接続を再利用できるようにします。
サーバーがボディサイズの分かっているレスポンスを送る場合、Content-Length ヘッダーによってクライアントは適切な量のメモリを確保し、ダウンロード中に正確な進捗表示を行えます。宣言された長さと実際のボディサイズが食い違う場合は、転送が途中で切れているか破損していることを示します。
このヘッダーは chunked の Transfer-Encoding とは排他的です。サーバーがサイズ不明のレスポンスをストリーミングする場合、固定のコンテンツ長の代わりに chunked エンコーディングが使われます。HTTP/2 と HTTP/3 では、プロトコルのレベルでフレーミングがメッセージの境界を扱いますが、Content-Length はボディサイズの検証のために引き続き有効です。
値はメッセージボディのオクテット(バイト)数を表す 1 つの非負整数です。
例
サーバーが 3,495 バイトの JSON レスポンスを返します。クライアントはちょうど 3,495 バイトを読み取ってから、メッセージが完了したとみなします。
Content-Length: 3495
POST リクエストがフォームのボディを送ります。Content-Length ヘッダーは、リクエストボディで何バイトを期待すべきかをサーバーに伝えます。
POST /submit HTTP/1.1
Host: example.re
Content-Type: application/x-www-form-urlencoded
Content-Length: 27
field=value&other=something
chunked 転送エンコーディングを使うレスポンスは Content-Length ヘッダーを完全に省略します。Transfer-Encoding ヘッダーが優先されます。
Transfer-Encoding: chunked
トラブルシューティング
転送の失敗や接続エラーは、誤ったあるいは矛盾する Content-Length の値にさかのぼれることがよくあります。
転送が中断される、あるいはダウンロードが部分的になる。クライアントが Content-Length の宣言より少ないバイト数しか受け取らず、切り詰められたレスポンスとして報告します。よくある原因は、オリジンが接続を早期に閉じている、プロキシのタイムアウトが転送を打ち切っている、サーバーがボディサイズを誤って計算している、などです。curl -v https://example.re/file を実行し、Content-Length ヘッダーの値と実際に受信したバイト数(転送のサマリーに表示されます)を比較してください。食い違いがあれば、この問題だと確認できます。
chunked エンコーディングと Content-Length の両方が存在する。同じレスポンスで Transfer-Encoding: chunked と Content-Length の両方を送ることは HTTP 仕様に違反します。Transfer-Encoding が存在する場合、クライアントは Content-Length を無視しなければなりませんが、すべての実装がこの規則に従うわけではありません。chunked エンコーディングを使う場合は Content-Length を削除してください。nginx では、ボディサイズが不明な場合に chunked エンコーディングが自動的に適用され、その際 nginx は Content-Length を省略します。両方のヘッダーを設定する独自のアプリケーションコードやミドルウェアは修正が必要です。
ミドルウェアがボディを変更した後に Content-Length が誤りになる。コンテンツを挿入するミドルウェア(アナリティクスのスクリプト、セキュリティトークン、デバッグツールバー)は、Content-Length を更新しないままボディサイズを変えてしまいます。その結果、ブラウザは表示されるコンテンツを切り詰めるか、決して届かないバイトを待ち続けます。Content-Length の計算は、ボディの変更がすべて完了した最終段階へ移してください。Express.js では compression ミドルウェアがこれを自動的に処理します。独自の構成では、Content-Length を削除して代わりに chunked エンコーディングに頼ります。
HEAD のレスポンスが誤った Content-Length を運ぶ。HEAD のレスポンスは、対応する GET のレスポンスが運ぶものと同じ Content-Length を、ボディなしで含めなければなりません。一部のフレームワークは Content-Length を 0 にした HEAD レスポンスを生成したり、ヘッダーを完全に省略したりします。curl -I https://example.re/resource(HEAD)と curl -s -o /dev/null -w ’%{size_download}’ https://example.re/resource(GET のボディサイズ)を比較して確認してください。値が食い違うと、リソースのサイズ判定に HEAD を利用するダウンロードマネージャーやキャッシュプロキシが壊れます。
curl で Content-Length の問題を診断する。curl -v https://example.re/resource を実行すると、詳細出力に Content-Length ヘッダーと転送バイト数が表示されます。Content-Length: N の行が宣言されたサイズを示します。末尾の bytes received が実際の転送量を示します。-o /dev/null を加えるとボディを破棄してヘッダーに集中できます。圧縮されたレスポンスでは、Content-Length が元のサイズではなく圧縮後のサイズを反映する点に留意してください。