はじめに
CloudFrontを利用している際に以下の問題が発生した。
アプリケーションで静的ファイルの後ろにクエリ文字列を付けて最新化させるということをしていたのだが、CloudFrontでクエリ文字列を変えてもキャッシュが新しくならないということがあった。
この記事では、CloudFrontでクエリ文字列付きのファイルについて、クエリ文字列ごとにキャッシュキーを設定するということを行う。
環境
AWS
  - EC2
  - CloudFront
  - ACM検証時の構成
以下の記事で作成した構成と同様となる。
CloudFrontのキャッシュを手動で削除する#全体の構成
クエリ文字列とCloudFrontのキャッシュの関係
基本的な動作
デフォルトでは、CloudFrontはURLのクエリ文字列をキャッシュキーに含めまない。
つまり、以下のURLにアクセスした場合:
https://example.cloudfront.net/image.jpg?version=1
https://example.cloudfront.net/image.jpg?version=2同じオブジェクト(image.jpg)がキャッシュされ、クエリ文字列は無視されるようになっている。
キャッシュキーとクエリ文字列
CloudFrontでクエリ文字列の処理を設定するには、「キャッシュポリシー」を利用する。
キャッシュポリシーでは、以下のことが設定できる。
- クエリ文字列を全て含める
- 特定のクエリ文字列のみを含める
- クエリ文字列を完全に除外する(デフォルト)
CloudFrontの設定 - クエリ文字列をキャッシュキーとしてキャッシュする
今回の目的としては、静的ファイルへのアクセスに対してクエリ文字列が付与されていた場合にクエリ文字列ごとキャッシュするということである。
カスタムキャッシュポリシーを使用しているが、マネージドポリシーのUseOriginCacheControlHeaders-QueryStrings でもできる気がする。
- UseOriginCacheControlHeaders-QueryStrings
 https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/using-managed-cache-policies.html#managed-cache-policy-origin-cache-headers-query-strings
カスタムキャッシュポリシーの作成
1. CloudFrontコンソールの「ポリシー」セクションで「キャッシュポリシー」を選択

2. 「キャッシュポリシーを作成」を選択

3. ポリシーの詳細を入力し、 「キャッシュポリシーを作成」をする
マネージドポリシーにある CachingOptimized を参考にクエリ文字列ごとキャッシュする形となる。
| 項目 | 設定内容 | 
|---|---|
| 名前 | CachingOptimizedCustom | 
| 説明 | |
| 最小 TTL | 1 秒 | 
| 最大 TTL | 31,536,000 秒 (1年) | 
| デフォルト TTL | 86,400 秒 (1日) | 
| ヘッダー | なし | 
| Cookie | なし | 
| クエリ文字列 | すべて | 
| 圧縮サポート | Gzip, Brotli | 

※ 付与するクエリ文字列がわかっている場合であれば、「クエリ文字列」の欄で「指定したクエリを文字列に含める」を使用してキャッシュするキーを限定したほうが良いと思われる。
4. 「Behaviors」タブを選択し、対象のビヘイビアを選択して「編集」を選択する
対象となるのは静的ファイルに関連する部分となるので、以下の赤枠の部分を編集する。

5. 作成したポリシーをディストリビューションの対象のビヘイビアのポリシーとして適用する

適用後

動作検証
動作の確認として、以下の記事で使用した静的ファイルを利用する。
CloudFrontのキャッシュを手動で削除する#静的ファイル
ここで、静的ファイルについては index.htmlの以下の部分を直すことにする。
-  <link rel="stylesheet" href="style.css" />
+  <link rel="stylesheet" href="style.css?v=20250410" />
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>Welcome to Nature</title>
  <link rel="stylesheet" href="style.css?v=20250410" />
</head>
<body>
  <header class="hero">
    <div class="overlay">
      <h1 class="title">自然とともに生きる</h1>
      <p class="subtitle">Find peace in the great outdoors</p>
      <a href="#explore" class="btn">探検する</a>
    </div>
  </header>
  <section id="explore" class="content fade-in">
    <h2>ようこそ</h2>
    <p>このページはアウトドアの魅力を紹介するデモサイトです。</p>
  </section>
  <script src="script.js"></script>
</body>
</html>確認
初回アクセス
?v=20250410 を付けた直後にアクセスをした場合、Miss from cloudfrontとなる。
Crtl+F5で強制リロードした後に確認、Hit from cloudfrontとなる。
ここまでは想定通り。
クエリ文字列の変更してアクセス
index.htmlのクエリ文字列を以下に変更する。
-  <link rel="stylesheet" href="style.css?v=20250410" />
+  <link rel="stylesheet" href="style.css?v=20250420" />
?v=20250420 を付けた直後にアクセスをした場合、Miss from cloudfrontとなる。
Crtl+F5で強制リロードした後に確認、Hit from cloudfrontとなる。
OK!
クエリ文字列もキャッシュキーにちゃんと含まれていそうだ!
よくある間違いと回避策
間違い1: すべてのクエリ文字列をキャッシュする
https://example.cloudfront.net/product.html?id=123&user=456&session=789このようなURLでは、user や session のような一時的な値によってキャッシュが断片化してしまう。
回避策: 必要なパラメータ(この場合はid)のみをキャッシュキーに含めるポリシーを作成する。
間違い2: キャッシュするべきパラメータを除外する
バージョン管理などで使われるクエリ文字列を無視すると、古いバージョンがキャッシュされ続ける可能性がある。
回避策: バージョン情報などのキャッシュ制御に重要なパラメータは、キャッシュキーに含めるようにする。
参考
- Amazon CloudFront でのクエリ文字列パラメータに基づいたコンテンツのキャッシュ https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/QueryStringParameters.html 
- Cloudfront用キャッシュポリシーの作成 https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/controlling-the-cache-key.html 
おわりに
CloudFrontでクエリ文字列をキャッシュキーに含めるように設定を行ってみた。CloudFrontはかなり強力なCDNなので理解せずに使うとこのあたりではまりそうだと思ったので勉強をしてみた。
まだまだ理解ができていない部分が多いので、勉強しつつアウトプットをしていきたい。CloudFrontの設定もそうだが、HTTPやWeb全般の知識が必要になってくるな…。