gazou-compressor.jp

画像CDNとキャッシュ制御の最適解 — Cache-Control/SWR/immutable/ETag

画像の体験はキャッシュ戦略で決まります。更新されないアセットは“強いキャッシュ”で固定し、 頻繁に変わる画像はSWR(stale-while-revalidate)で整合性と体感を両立。Vary: Acceptの濫用や CDNキー設計のミスは、ヒット率低下や遅延の温床です。本稿は実務に直結する“最短解”をテンプレとともに示します。

先に結論(このルールで始める)
  • ハッシュ付き静的画像:public, max-age=31536000, immutable
  • 差し替え頻度が高い画像:public, max-age=300, stale-while-revalidate=86400
  • フォーマットは拡張子分岐+srcset/sizesで配信。Vary: Acceptは最小限。
  • 差し替えはURLバージョン(指紋)で行い、CDNパージは例外対応に限定。

要点(TL;DR)

  • ハッシュ付き静的はimmutable、可変はSWR
  • Vary: Acceptを濫用しない。拡張子分岐+srcsetで単純に。
  • ETag/Last-Modifiedは未知の更新頻度に有効だが、往復は発生。
  • CDNのキャッシュキーとオリジンのヘッダー上書きに注意。

1. 戦略マトリクス(資産×ヘッダー)

資産例推奨ヘッダー理由
/assets/logo.abcd12.pngpublic, max-age=31536000, immutableURLが内容ハッシュなので安全に長期保存
/user/123/avatar.webppublic, max-age=300, stale-while-revalidate=86400即返しつつ裏で更新。体験と整合性の両立
/thumbs/article-*.webppublic, max-age=86400日次で変わる想定。ほどよい寿命

2. 結論テンプレ(そのまま使える)

# ハッシュ付き静的画像(/assets/logo.abcd12.png)
Cache-Control: public, max-age=31536000, immutable

# 差し替え頻度が高い画像(/user/123/avatar.webp)
Cache-Control: public, max-age=300, stale-while-revalidate=86400

# 受容ヘッダー出し分けをする場合のみ(CDNのキー設計が必須)
Vary: Accept

3. Vary: Accept を多用しない理由

  • CDNのキャッシュキーが増え、ヒット率が低下。オリジン到達が増えて遅延・コスト増。
  • 代替は拡張子分岐.avif/.webp/.jpg)+ HTML の srcset/sizes。 単純で運用ミスが少ない。

4. 設定例(サーバ/エッジ)

A. Next.js Route Handler

// app/images/[file]/route.ts
import { NextResponse } from "next/server";
export async function GET(_: Request, { params }: { params: { file: string } }) {
  const file = params.file;
  const res = await fetch("https://origin.example.com/images/" + file);
  const headers = new Headers(res.headers);
  headers.set("Cache-Control", "public, max-age=300, stale-while-revalidate=86400");
  return new NextResponse(res.body, { headers, status: res.status });
}

B. Nginx(静的配信)

location ~* \.(avif|webp|jpg|jpeg|png|gif|svg)$ {
  add_header Cache-Control "public, max-age=31536000, immutable";
}

5. ETag/If-None-Match の使いどころ

更新頻度が読めない場合は ETag で差分転送。ただしヘッダー往復は発生するため、 回線が細い地域では“強いキャッシュ”のほうが体験が良い場面も多いです。迷ったら「指紋URL+immutable」を第一選択に。

6. 検証と監視(チェック手順)

  • ヘッダー確認:
    curl -I https://example.com/assets/logo.abcd12.png
  • CDNのヒット率(CF-Cache-Status / X-Cache 等)を監視。
  • 差し替えはURLバージョンで実施(パージ乱用はしない)。

7. 運用の落とし穴

  • CDNでのヘッダー上書きにより、オリジンの意図が無効化される。
  • URLハッシュ運用なのにpurgeを多発して二重運用になっている。
  • Varyやクエリパラメータがキーを分断し、ヒット率を落としている。

8. まとめ:immutable×SWRの二刀流で堅く速く

画像キャッシュは「変わらないものはimmutable」「変わるものはSWR」が基本。srcset/sizes と組み合わせて 過大ダウンロードを避け、優先度設計でLCPにも効かせましょう。

gazou-compressor.jp 編集部
画像圧縮・変換・背景除去などの実践テクニックと、Webで“速く・軽く・崩さない”ためのノウハウを発信しています。

関連記事