広告が嫌いですか? 行く 広告なし 今日

gzip、Brotli、Zstd content-encoding: identity を誤って設定した開発者のための HTTP 壊し方

更新日

HTTP圧縮交渉の仕組み(Accept-Encoding / Content-Encoding)、gzip、Brotli、Zstd の並列ベンチマーク、curl で圧縮が実際に動作しているかを確認する方法、および4つの誤設定が静かにそれを無効化する方法を説明します。

gzip、Brot或いはZstd:content-encoding: identityを誤って設定する開発者のためのHTTP圧縮 1

あなたの nginx 設定には gzip on;があります。アプリは JSON を返します。レスポンスボディはまだ圧縮されていない状態で 35KB です。エラーも警告もありません — 壊れていませんが、圧縮が静かに実行されていません。

これは通常、4つの誤設定のいずれかです。しかしまず、交渉が実際にどのように機能するかを確認します。

HTTP 壊れ圧縮交渉の仕組み

2つのヘッダー、それ以外は一切ありません。クライアントは、どのアルゴリズムを解圧できるかを Accept-Encodingに発表します。サーバーはアルゴリズムを選択し、ボディを圧縮し、その選択を Content-Encoding:

GET /api/data HTTP/1.1
Host: example.com
Accept-Encoding: gzip, deflate, br, zstd
HTTP/1.1 200 OK
Content-Type: application/json
Content-Encoding: br
Vary: Accept-Encoding

Vary: Accept-Encoding ヘッダーは、CDN キャッシュの正確性を気にする場合に必須です。このヘッダーがないと、CDN は Brotli 圧縮されたレスポンスをキャッシュし、クライアントが only advertised gzipAccept-Encodingにしか発表していない場合、そのクライアントは Brotli を gzip として解圧しようとし、ゴミを取得します。nginx の gzip_vary on; はこれを自動的に追加します。

Content-Encoding: identity は技術的に有効ですが、「圧縮なし」という意味です — しかし誰も明示的に設定しません。実際の失敗モードは逆です:あなたが期待するはずの場所に Content-Encoding ヘッダーがまったく存在しません。

圧縮が実際に機能しているかを確認する

デバッグ設定を行う前に、問題を確認します。

# Check headers only
curl -sI -H "Accept-Encoding: gzip, br, zstd" https://example.com/api/data   | grep -i "content-encoding\|vary"

# Compare compressed vs uncompressed size
curl -so /dev/null -w "uncompressed: %{size_download} bytes
" https://example.com/api/data
curl -so /dev/null --compressed -w "compressed:   %{size_download} bytes
" https://example.com/api/data

--compressed を送信し、レスポンスを自動的に解圧します。両方の数字が一致する場合、圧縮が実行されていません。すべてのレスポンスヘッダーと、それぞれのヘッダーが文脈で意味を持つように確認したい場合は、 Accept-Encoding: deflate, gzip, br, zstd はそれらを注釈付けし、 HTTPヘッダーアナライザー 、および cache-control ディレクティブを含みます。 Vary, Content-Encodinggzip と Brotli と Zstd

今日の HTTP で実際に関連性があるアルゴリズムは3つです。以下のベンチマークデータは、

Zstd 官方ベンチマーク の Silesia コルパス — 混合された現実のファイル(HTML、ソースコード、PDF、データベース)を標準データセットとして、Core i7-9700K でテストされたものです。純粋な JSON またはプレーンテキストのペイロードは通常、圧縮がよく効果的です。 gzip

アルゴリズムレベル比率圧縮展開
1(高速)2.74x69 MB/s380 MB/s380 MB/s
1(高速)6(デフォルト)2.97x29.9 MB/s360 MB/s
1(高速)9(最大)3.10x18 MB/s360 MB/s
Brotli43.18x104 MB/s440 MB/s
Brotli11(最大)3.74x0.4 MB/s440 MB/s
Zstd2.74x2.88x430 MB/s1,380 MB/s
Zstd3(デフォルト)3.01x320 MB/s1,350 MB/s
Zstd19(最大)3.40x17.5 MB/s1,380 MB/s

1(高速) は基準です。レベル6は即時処理の正しい選択です — レベル6からレベル9に移行する場合、CPU 使用量が65%増加し、得られる比率が約4%改善しますが、動的応答には価値がありません。事前に圧縮された静的ファイルは別の計算です。

Brotli は、同等のCPUコストでレベル4-6においてgzipを真正に上回り、解圧速度が約20%速くなります。理由は、Brotliはウェブコンテンツに最適化された静的辞書を持っているため — HTMLエンティティ、HTTPフィールド名、JavaScriptキーワードです。同じ素材に対して一般用途の圧縮器よりも高い比率を達成します。レベル11は、事前に圧縮された静的資産にのみ適用可能です。圧縮速度が0.4 MB/sであるため、約25MB/分の圧縮が可能です。これはビルドステップであり、リクエストハンドラーではありません。

Zstd は速度に関する話です。デフォルトレベル(3)はgzipの比率を達成していますが、圧縮速度が10倍速く、解圧速度がほぼ4倍速くなります。主な制限はブラウザのサポートです:Chrome 118以降(2023年10月)、Firefox 126以降(2024年5月)、Safari 18以降(2024年末)。まだ全ブラウザでサポートされていないため、単一アルゴリズムとして使用することはできませんが、サーバーが適切に交渉している場合、Zstdを追加すると数行の設定を必要とし、Brotliを宣言するクライアントに役立ちます。レベル19のZstdは、Brotli-11の比率に近づきながら、圧縮速度の深刻なペナルティを回避し、高圧縮要件の即時処理により利用可能になります。

ブラウザおよびクライアントのサポート

アルゴリズムChromeFirefoxSafariEdgeNode.js
1(高速)すべてすべてすべてすべて組み込み(zlib)
deflateすべてすべてすべてすべて組み込み(zlib)
Brotli (br)51+44+11+15+v10.16+
Zstd118+126+18+118+v21+

重要な特徴: brzstd はHTTPS接続でのみ表示されます。ブラウザは、明確なHTTP接続ではそれを発表しない — MITM攻撃によるエンコーディングヘッダーの注入を防ぐためです。テスト中に Accept-Encoding で、なぜだけ http://localhost が表示されないのか、その理由です。HTTPSでテストするか、curlを直接使用してください(curlはこの制限を適用しません)。 gzip, deflate4つの静かに破綻する誤設定

1. gzip_proxied が欠落(nginx リバースプロキシ)

nginx の

モジュールは、nginxが自ら生成するレスポンスを圧縮します。プロキシリクエスト(上流アプリからnginxに、クライアントへ)の場合、あなたは gzip が必要です — そうでなければ、nginxは自らのコンテンツハンドラーからのレスポンスのみを圧縮し、上流からのレスポンスは圧縮しません。 gzip_proxied ほとんどのnginx設定はリバースプロキシです。ほとんどのチュートリアルは proxy_pass を省略しています。これらの2つの事実が、多くの静かに圧縮されていないレスポンスを説明しています。

# This is NOT enough when nginx is a reverse proxy:
gzip on;
gzip_types text/plain application/json application/javascript text/css;

# You need this too:
gzip_proxied any;

2. MIMEタイプが gzip_types に含まれていない gzip_proxiednginx のデフォルト

のみです。JSON、CSS、JavaScript、SVG — すべてが明示的にリストされていない限り、圧縮されません:

nginx はベース MIME タイプに基づいてマッチしますので、 gzip_typestext/html

gzip_types
  text/plain
  text/css
  text/xml
  text/javascript
  application/json
  application/javascript
  application/xml
  application/rss+xml
  image/svg+xml;

をカバーします。charsetのバリエーションを別々にリストする必要はありません。 application/json 3. 中間プロキシが Accept-Encoding を削除 application/json; charset=utf-8AWS ALB、誤設定された Cloudflare Workers、および一部の API ゲートウェイ設定は、

を削除または変更します。サーバーはこのヘッダーを確認せず、デフォルトで圧縮を無効にし、すべてのダウンストリームのシステムが機能が壊れていると誤認します。チェーンのどこにもエラーは表示されません。

デバッグには、オリジンレスポンスとCDNレスポンスを比較します: Accept-Encoding オリジンが

を直接返すが、CDNレスポンスには

# Via CDN/proxy
curl -sI -H "Accept-Encoding: gzip, br" https://example.com/api/data

# Direct to origin (bypassing CDN via --resolve or direct IP)
curl -sI -H "Accept-Encoding: gzip, br" --resolve "example.com:443:ORIGIN_IP" https://example.com/api/data

が存在しない場合、CDNが何かを削除している可能性があります — おそらく、 Content-Encoding: gzip をインバウンドで削除しているため、オリジンが最初から圧縮されないのです。 Content-Encoding4. 上流アプリが圧縮し、nginxが再度圧縮を試みる Accept-Encoding あなたの Node.js/Go/Python アプリがレスポンスボディを圧縮し、

を設定している場合、nginx は二重圧縮を回避すべきですが、これはヘッダーのタイミングに依存します。上流がストリーム中でヘッダーを送信するか、nginx の検出が競合する場合、クライアントが解圧できない二重圧縮されたゴミが得られます。

クリーンな解決策:nginx がすべての圧縮を所有するようにします。アプリ内の圧縮ミドルウェア(express の Content-Encoding: gzipモジュール、Go の

、など)を削除し、プレーンレスポンスを返し、nginx がエッジで圧縮を行うようにします。同じパフォーマンスの向上を得ることができ、二重圧縮のリスクがありません。 compression 機能する設定 gzip.Handlernginx

Apache

Caddy

gzip on;
gzip_vary on;         # adds Vary: Accept-Encoding automatically
gzip_proxied any;     # compress responses from proxied upstreams
gzip_comp_level 6;
gzip_min_length 256;  # skip tiny responses where overhead isn't worth it
gzip_types
  text/plain
  text/css
  text/xml
  text/javascript
  application/json
  application/javascript
  application/xml
  application/rss+xml
  image/svg+xml;

# Brotli requires the ngx_brotli module
# https://github.com/google/ngx_brotli
brotli on;
brotli_comp_level 4;
brotli_static on;     # serve pre-compressed .br files when they exist
brotli_types
  text/plain
  text/css
  application/json
  application/javascript
  image/svg+xml;

Caddy は gzip および Brotli をデフォルトで有効にします。Zstd を明示的に追加するには:

LoadModule deflate_module modules/mod_deflate.so
AddOutputFilterByType DEFLATE text/html text/plain text/css   application/json application/javascript image/svg+xml
Header append Vary Accept-Encoding

# mod_brotli requires Apache 2.4.26+
LoadModule brotli_module modules/mod_brotli.so
AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/css   application/json application/javascript image/svg+xml

MIMEタイプリスト、または

のエッジケース、正しい

example.com {
  encode gzip zstd br
  reverse_proxy localhost:3000
}

の処理がデフォルトで行われます。『どのサーバーが圧縮関連の誤設定面積が最も少ないか』という質問への誠実な答えは Caddy です。 gzip_proxied 自分のペイロードで圧縮をテストする Vary Silesia コルパスのベンチマークデータは相対的なパフォーマンスを示しますが、あなたの特定のペイロードがより重要です。再現性のあるフィールド名を持つJSON APIレスポンスは、minified JavaScriptや混合HTMLと異なります。これらのツールは、ローカルの圧縮サーバーを起動せずに、ブラウザ内で特定のペイロードをテストできます:

— ペイロードを貼り付け、即座に圧縮サイズと比率を確認

— Brotli圧縮を異なる品質レベルでテスト

が圧縮なしを確認している場合、解決策は上記の4つの誤設定のいずれかです — 最も可能性が高いのは

まとめ

のnginx、またはCDNがあなたの curl -sI ヘッダーを食い尽くしていることです。直接オリジンを確認し、サーバー設定を責める前に確認してください。 Content-Encodingアルゴリズムの選択に関して:動的APIレスポンスにはgzip-6が十分であり、設定リスクはほとんどありません。静的資産にはBrotliを追加してください — ビルドステップでレベル11で事前に圧縮し、 gzip_proxied any; を設定し、Brotliを宣言しないクライアントにはgzipに自動的に切り替えるようにします。Zstdは今すぐ追加すべきです;設定コストは非常に小さく、ブラウザのフィートポールが急速に成長しています。すべてのアルゴリズムを正しく Accept-Encoding 処理できるようにすることは、新しいシステムにとって適切な姿勢です。

gzip、Brotli、Zstd:HTTP圧縮、コンテンツ-エンコーディング:identityを誤って設定した開発者向け2 brotli_static ongzip、Brotli、Zstd:HTTP圧縮、コンテンツ-エンコーディング:identityを誤って設定した開発者向け1 br。Zstdは今、追加すべきです。設定コストは微小であり、ブラウザのサイズは急速に増加しています。正しい処理を提供することは、新しいものの正しい姿です。 Vary: Accept-Encoding 処理は、新しいものの正しい姿です。

広告なしで楽しみたいですか? 今すぐ広告なしで

拡張機能をインストールする

お気に入りのブラウザにIOツールを追加して、すぐにアクセスし、検索を高速化します。

に追加 Chrome拡張機能 に追加 エッジ拡張 に追加 Firefox 拡張機能 に追加 Opera 拡張機能

スコアボードが到着しました!

スコアボード ゲームを追跡する楽しい方法です。すべてのデータはブラウザに保存されます。さらに多くの機能がまもなく登場します!

ニュースコーナー 技術ハイライト付き

参加する

価値ある無料ツールの提供を継続するためにご協力ください

コーヒーを買って