Cloudflareのキャッシュ状況を実測する|HIT/MISS・キャッシュ率・静的アセット配信を確認

CloudflareのHTTPトラフィックとCF-Cache-Statusを実測。過去24時間のキャッシュリクエスト1.26k、キャッシュ帯域幅25.22MBを確認し、通常記事でMISS→HIT、トップページとWebPでHITを確認した記録。

公開:更新:
Cloudflareのキャッシュ状況を実測する|HIT/MISS・キャッシュ率・静的アセット配信を確認

Cloudflareの管理画面でキャッシュ状況は見えても、「実際のページはHITしているのか」「静的画像も同じ動きなのか」「max-age=0なのにHITと表示されるのはどういう状態か」と気になることがあります。

ゆまラボでは2026年9月23日にHTTPトラフィックと実際のレスポンスヘッダーを確認しました。過去24時間はリクエスト1.69kのうちキャッシュ1.26k、帯域幅31.07MBのうちキャッシュ25.22MB。PowerShellから同じ記事URLを2回取得すると、MISS → HITへ変化するところも確認できました。

この記事では、Cloudflare管理画面の集計値とCF-Cache-Statusを使い、トップページ、通常記事、/_astro/配下のWebP画像が実際にどう配信されているかを確認します。設定変更やキャッシュ削除は行わず、公開中の状態をそのまま測定しました。

人気記事を自動表示するならGA4とCloudflare Analyticsどちらを使う?では、Cloudflareのトラフィック概要でキャッシュヒット率49.59%まで確認していた。

当時は管理画面の数字を見るところで終了している。今回は個別URLのレスポンスヘッダーまで確認し、管理画面の集計と実際の配信状態をつなげてみる。

HTTPトラフィックでキャッシュリクエストを確認する#

Cloudflare Dashboardでbringain.comを開き、Analytics & Logs > HTTP Trafficを確認した。

期間は過去24時間。

リクエスト側では次の値が表示された。

Cloudflare HTTPトラフィックで過去24時間のリクエスト1.69k、キャッシュ1.26k、非キャッシュ423を確認した画面

横にスクロールできます
項目過去24時間
リクエストの合計数1.69k
キャッシュリクエスト1.26k
非キャッシュリクエスト423

画面上のk表記は丸められているので厳密な比率計算には向かない。表示値から見ると、リクエスト数ベースではおよそ75%がキャッシュ側になる。

以前の記事で見た49.59%より高い数字だが、計測日と対象期間が違う。49.59%から約75%へ改善した、といった比較には使わない。

ここで確認したかったのは、現在の公開サイトでキャッシュ配信が相当数発生していることだった。

帯域幅では25.22MBがキャッシュ側#

同じHTTP Traffic画面で帯域幅へ切り替えると、別の見え方になる。

Cloudflare HTTPトラフィックで総帯域幅31.07MB、キャッシュ帯域幅25.22MB、非キャッシュ帯域幅5.85MBを確認した画面

横にスクロールできます
項目過去24時間
総帯域幅31.07 MB
キャッシュ帯域幅25.22 MB
非キャッシュ帯域幅5.85 MB

25.22 ÷ 31.07で、帯域幅ベースでは約81.2%がキャッシュ側だった。

リクエスト側の約75%より高い。画像やCSSなど、容量を持つ静的アセットがキャッシュから配信されていると、リクエスト件数と転送量で割合が変わることはあり得る。

ただ、管理画面だけでは「どのURLがHITしたか」までは今回の画面から分からない。次はHTTPレスポンスを直接確認した。

PowerShellからCF-Cache-Statusを確認する#

トップページと、実際に公開中の/_astro/配下のWebP画像を2回ずつ取得した。

使用したコマンドはこれ。

$urls = @(
  'https://bringain.com/',
  'https://bringain.com/_astro/series-site-operation-seo-sns-logo.BK0yY7N2_yo8sT.webp'
)

foreach ($url in $urls) {
  1..2 | ForEach-Object {
    "=== $url / request $_ ==="

    curl.exe -s -D - -o NUL $url |
      Select-String -Pattern '^(HTTP/|CF-Cache-Status:|Age:|Cache-Control:|ETag:|Last-Modified:|Content-Type:|CF-Ray:)'
  }
}

結果は、トップページもWebP画像も2回ともHIT

トップページとWebP画像でCF-Cache-Status HITを確認したPowerShell画面

トップページ  request 1  HIT
トップページ  request 2  HIT
WebP画像       request 1  HIT
WebP画像       request 2  HIT

Cloudflareの公式ドキュメントでは、CF-Cache-Status: HITは対象リソースがCloudflareのキャッシュ内で見つかり、キャッシュから応答した状態として説明されている。

管理画面でキャッシュリクエストが多いことは確認できていたが、これで個別のURLでもHITを直接確認できた。

max-age=0でもHITになっていた#

レスポンスを見て少し引っかかったのがCache-Controlだった。

トップページもWebP画像も次の値を返している。

Cache-Control: public, max-age=0, must-revalidate

WebP画像にはETagも付いていた。

ETag: "f4a2d334ebdc1e3e935c60e226f98ffa"

Cloudflare Workers Static Assetsの公式ドキュメントでは、静的アセットのデフォルトヘッダーとしてCache-Control: public, max-age=0, must-revalidateが案内されている。ブラウザは保存した内容を使う前に鮮度を再確認し、ETagを使った検証も行える。

同じ公式ページではCF-Cache-Statusも静的アセットのレスポンスヘッダーとして説明されており、HITならキャッシュから配信、MISSならキャッシュから配信されなかった状態になる。

今回の実測では、max-age=0という文字だけを見て「キャッシュされていない」と判断すると実態と合わなかった。確認するならCF-Cache-Statusまで見る必要がある。

Cloudflareでセキュリティヘッダーを設定したときも、管理画面の設定だけで判断せず実レスポンスまで確認した。キャッシュも同じ進め方が分かりやすかった。

通常の記事でMISSからHITへ変わった#

ここまでのURLは最初からHITだった。

「MISSも実際に確認できないか」と思い、通常の記事ページを2回連続で取得した。

対象は次の記事。

https://bringain.com/blog/sns-publishing-candidates/
$url = 'https://bringain.com/blog/sns-publishing-candidates/'

1..2 | ForEach-Object {
    "=== article / request $_ ==="

    curl.exe -s -D - -o NUL $url |
      Select-String -Pattern '^(HTTP/|CF-Cache-Status:|Age:|Cache-Control:|ETag:|Last-Modified:|Content-Type:|CF-Ray:)'
}

ここで狙っていた動きが出た。

同じ記事URLを2回取得して1回目MISS、2回目HITを確認したPowerShell画面

request 1
CF-Cache-Status: MISS

request 2
CF-Cache-Status: HIT

1回目はMISS、2回目はHIT

Cloudflareの現行ドキュメントでは、MISSはキャッシュ対象のレスポンスがリクエスト時点のキャッシュ内に存在しなかった状態、HITはキャッシュ内で見つかった状態として区別されている。

2026年5月にはキャッシュ不可レスポンスの扱いも変更されている。Cloudflareがキャッシュしないと判断した応答はBYPASSへ集約され、MISSはキャッシュ可能だがその時点で未格納だったケースを示すようになった。

今回の通常記事では、そのMISS → HITを同じクライアントから連続して確認できた。

クエリ文字列を付けたWebPは最初からHITだった#

MISSを出す前に、WebP画像へ毎回新しいクエリ文字列を付けるテストも行った。

$token = [guid]::NewGuid().ToString('N')
$url = "https://bringain.com/_astro/series-site-operation-seo-sns-logo.BK0yY7N2_yo8sT.webp?cachetest=$token"

最初は新しいURL扱いになってMISSが出ると考えていた。

実際の結果は1回目からHIT

ランダムなcachetestクエリを付けたWebP画像で1回目と2回目ともHITを確認したPowerShell画面

request 1  HIT
request 2  HIT

これは少し意外だった。

この実測だけで、ゆまラボの静的アセットに対するクエリ文字列とキャッシュキーの処理までは断定しない。MISSからHITへの変化を説明する材料には、挙動が明確だった通常記事の結果を使うことにした。

実測記事では、狙った結果が出なかった試行も残しておくと判断の経緯が分かりやすい。

Cache Rulesは作成していなかった#

HITが出ている理由を確認するため、CloudflareのRules > Cache Rulesも開いた。

CloudflareのCache Rules一覧でルールが作成されていないことを確認した画面

画面にはCache Rules は作成されていませんと表示されている。

今回の測定前に、HITを出すためのCache Ruleは追加していない。キャッシュ削除やDevelopment Modeの変更も行っていない。

Cloudflare Workers Static Assetsの公式ドキュメントでは、デプロイされたHTML、CSS、画像などの静的アセットをCloudflareのネットワーク上で自動的にキャッシュすると説明されている。ゆまラボでは今回、追加のCache Ruleを作らない状態でも実レスポンスでHITを確認できた。

ここは管理画面のキャッシュルールと、Workers Static Assetsの配信を分けて考える必要があった。

管理画面とレスポンスヘッダーを合わせて見る#

今回確認できた内容をまとめるとこうなる。

横にスクロールできます
確認箇所実測結果
HTTP Traffic・リクエスト合計1.69k / キャッシュ1.26k / 非キャッシュ423
HTTP Traffic・帯域幅合計31.07MB / キャッシュ25.22MB / 非キャッシュ5.85MB
リクエスト数ベース約75%がキャッシュ側
帯域幅ベース約81.2%がキャッシュ側
トップページHIT → HIT
/_astro/ WebP画像HIT → HIT
クエリ文字列付きWebPHIT → HIT
通常の記事ページMISS → HIT
Cache Rules作成なし

Cloudflareの管理画面ではサイト全体の傾向を確認できる。CF-Cache-Statusを見ると、個別URLがその瞬間にどの状態だったかまで追える。

この2つを合わせると、「キャッシュが効いていそう」という感覚より具体的に確認できた。

以前のLighthouse測定ではキャッシュ期間に関する指摘も出ていた。Lighthouseはページ読み込み時の改善候補を見る用途、今回の確認はCloudflare側の配信状態を見る用途になる。数字の役割を分けておくと判断しやすい。

今回の結果#

2026年9月23日時点のゆまラボでは、過去24時間のHTTPトラフィックでキャッシュリクエスト1.26k、キャッシュ帯域幅25.22MBを確認した。

PowerShellから実際のURLを取得すると、トップページとWebP画像はHIT。通常の記事ページでは1回目MISS、2回目HITとなり、キャッシュへ入る前後の状態まで確認できた。

Cache-Control: public, max-age=0, must-revalidateが返っている状態でもCF-Cache-Status: HITを確認している。ヘッダーを1項目だけ見るより、Cache-ControlETagCF-Cache-Statusを合わせて読む方が実際の配信状態を把握しやすい。

今回は設定変更を行っていない。現在の公開状態を測った記録として、この数値とレスポンスを残しておく。

参考#