この記事の要点
• Content-Encodingはレスポンスボディの圧縮方式を示すHTTPヘッダー
• Brotli(br)が現在の主流で、gzipより高圧縮率を実現
• Accept-Encodingでブラウザが対応する圧縮方式をサーバーに伝える
Content-Encodingとは
Content-Encodingは、HTTPレスポンスのボディがどの圧縮アルゴリズムで圧縮されているかを示すヘッダーです。圧縮により、転送データ量を削減し、ページの読み込み速度を大幅に改善できます。
なぜ必要か: HTMLやCSS、JavaScriptファイルは圧縮率が高く、テキストベースのコンテンツを70〜90%削減できます。モバイル環境では特に効果的です。
圧縮のネゴシエーション
ブラウザとサーバー間で、以下のフローで圧縮方式が決定されます。
1. ブラウザがリクエスト
ブラウザはAccept-Encodingヘッダーで対応する圧縮方式を伝えます。
GET /index.html HTTP/1.1
Host: example.com
Accept-Encoding: br, gzip, deflate
2. サーバーがレスポンス
サーバーは最適な圧縮方式を選択し、Content-Encodingヘッダーで通知します。
HTTP/1.1 200 OK
Content-Type: text/html
Content-Encoding: br
Content-Length: 1234
Vary: Accept-Encoding
ポイント: Vary: Accept-Encoding ヘッダーは、CDNやプロキシキャッシュに「Accept-Encodingの違いで異なるバージョンをキャッシュすること」を伝えます。
圧縮アルゴリズムの種類
主要な圧縮方式とその特徴を比較します。
| アルゴリズム | Content-Encoding | 圧縮率 | 圧縮速度 | 解凍速度 | ブラウザ対応 | 主な用途 |
|---|---|---|---|---|---|---|
| Brotli | br | 最高(110〜120%) | 遅い | 速い | モダンブラウザ | HTML/CSS/JS |
| gzip | gzip | 高(100%基準) | 速い | 速い | ほぼ全て | 汎用 |
| deflate | deflate | 高(gzipと同等) | 速い | 速い | ほぼ全て | レガシー |
| Zstandard | zstd | 最高(120%) | 最速 | 最速 | 未対応多い | 将来の標準候補 |
圧縮率の基準: gzipを100%とした場合、Brotliは同じサイズを110〜120%の効率(つまり10〜20%小さく)で圧縮できます。
Brotliが主流の理由
- 圧縮率の高さ: gzipより10〜20%小さく圧縮
- 解凍速度: 圧縮は遅いが、解凍はgzipと同等
- 事前圧縮との相性: 静的ファイルは事前圧縮できるため、圧縮速度の遅さが問題にならない
- ブラウザ対応: Chrome 50+、Firefox 44+、Safari 11+など主要ブラウザで対応
実践メモ: 静的ファイルはビルド時にBrotli圧縮しておき、動的コンテンツはgzipを使うのが一般的です。
各圧縮方式の詳細
Brotli(br)
最新かつ最も効率的な圧縮方式です。
Content-Encoding: br
特徴:
- 圧縮レベル: 0(無圧縮)〜 11(最高圧縮)
- レベル4〜6が圧縮速度とサイズのバランスが良い
- 静的ファイルにはレベル11を推奨
設定例(Nginx):
http {
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/json application/javascript text/xml application/xml;
# 静的ファイルの事前圧縮版を使用
brotli_static on;
}
gzip
最も広くサポートされている圧縮方式です。
Content-Encoding: gzip
特徴:
- 圧縮レベル: 1(最速)〜 9(最高圧縮)
- レベル6がデフォルト、バランスが良い
- 全ブラウザで対応
設定例(Apache):
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css application/javascript
DeflateCompressionLevel 6
deflate
古い圧縮方式で、現在はあまり使われません。
Content-Encoding: deflate
特徴:
- gzipとほぼ同じアルゴリズム(DEFLATE)
- ヘッダーの実装にブラウザ間で差異があった歴史的問題
- 新規実装では推奨されない
Zstandard(zstd)
将来の標準候補ですが、現時点ではブラウザ対応が限定的です。
Content-Encoding: zstd
特徴:
- Brotliより高速で高圧縮
- Chrome 123+、Firefox 126+で実験的サポート
- サーバー間通信では既に採用例あり
圧縮対象の選定
圧縮すべきファイル
- HTML、CSS、JavaScript
- JSON、XML、SVG
- テキストベースのフォント(.svg、.ttf)
- テキスト形式の設定ファイル
圧縮すべきでないファイル
- 既に圧縮済みの画像(JPEG、PNG、WebP)
- 動画ファイル(MP4、WebM)
- 圧縮済みアーカイブ(ZIP、GZIP)
- 小さいファイル(1KB以下)
注意: 既に圧縮されているファイルを再圧縮すると、CPU負荷だけ増えてサイズは減らない場合があります。MIMEタイプで判定しましょう。
実装例と設定
Node.js(Express)
const compression = require('compression');
const express = require('express');
const app = express();
// 動的コンテンツをgzip圧縮
app.use(compression({
level: 6,
threshold: 1024, // 1KB以上のみ圧縮
filter: (req, res) => {
if (req.headers['x-no-compression']) {
return false;
}
return compression.filter(req, res);
}
}));
// 静的ファイルの事前圧縮版を優先配信
app.use(express.static('public', {
extensions: ['br', 'gz']
}));
Cloudflare(CDN設定)
Cloudflareは自動的にBrotli圧縮を適用します。
// Worker でカスタム制御
export default {
async fetch(request) {
const response = await fetch(request);
const acceptEncoding = request.headers.get('accept-encoding') || '';
if (acceptEncoding.includes('br')) {
// Brotli対応ブラウザ
return new Response(response.body, {
...response,
headers: {
...response.headers,
'Content-Encoding': 'br',
},
});
}
return response;
}
};
圧縮効果の確認
ブラウザDevToolsで確認
Chrome DevTools のネットワークタブで、以下を確認できます。
- Size: 圧縮後のサイズ
- Content: 元のサイズ
- Content-Encoding: 使用された圧縮方式
コマンドラインで確認
# レスポンスヘッダーを確認
curl -I -H "Accept-Encoding: br, gzip" https://example.com/
# 圧縮率を比較
curl -H "Accept-Encoding: gzip" https://example.com/ --compressed | wc -c
curl -H "Accept-Encoding: br" https://example.com/ --compressed | wc -c
パフォーマンス最適化のベストプラクティス
1. 静的ファイルは事前圧縮
# ビルド時にBrotli圧縮
find dist -type f \( -name "*.html" -o -name "*.css" -o -name "*.js" \) \
-exec brotli -q 11 -o {}.br {} \;
# gzip版も生成(フォールバック用)
find dist -type f \( -name "*.html" -o -name "*.css" -o -name "*.js" \) \
-exec gzip -9 -k {} \;
2. 適切な圧縮レベルを選択
| 用途 | Brotli | gzip |
|---|---|---|
| 静的ファイル(事前圧縮) | 11 | 9 |
| 動的コンテンツ | 4〜6 | 4〜6 |
| リアルタイムAPI | 使用しない | 1〜3 |
3. Varyヘッダーを必ず付与
Vary: Accept-Encoding
これにより、CDNが圧縮形式ごとに異なるキャッシュを保持します。
ポイント: 事前圧縮ファイルは元ファイルと同じディレクトリに `.br` / `.gz` 拡張子で配置すると、Nginx/Apacheが自動的に配信してくれます。
トラブルシューティング
圧縮が効かない場合
確認ポイント:
- Accept-Encodingヘッダーが送信されているか
- サーバーが圧縮機能を有効にしているか
- ファイルサイズが閾値(通常1KB)以上か
- MIMEタイプが圧縮対象に含まれているか
例(Nginx):
# 圧縮が効かない場合の診断
error_log /var/log/nginx/error.log debug;
Content-Length の不一致
圧縮すると元のサイズと異なるため、Content-Lengthを更新する必要があります。多くのWebサーバーは自動で行いますが、カスタム実装では注意が必要です。
// ✗ 悪い例: 元のサイズをそのまま返す
res.setHeader('Content-Length', originalSize);
// ✓ 良い例: 圧縮後のサイズを返す
const compressed = await compress(data);
res.setHeader('Content-Length', compressed.length);
まとめ
Content-Encodingは、Webパフォーマンス最適化の基本です。Brotli圧縮を適切に導入することで、転送データ量を大幅に削減し、ユーザー体験を向上させることができます。静的ファイルは事前圧縮、動的コンテンツは適切な圧縮レベルで、効率的な配信を実現しましょう。
参考リソース
- MDN - Content-Encoding
- MDN - Accept-Encoding
- RFC 9110 - HTTP Semantics (Content-Encoding)
- Brotli Compression Algorithm (RFC 7932)
- Google - Brotli Compression
- Can I use - Brotli