[小ネタ] CloudFrontでクエリ文字列を転送しているときのInvalidationにはクエリ文字列を忘れないように注意しよう
はじめに
清水です。タイトルのとおりなのですが、Amazon CloudFrontでクエリ文字列をオリジンに転送するよう設定している場合でInvalidation(ファイルの無効化)を行う際には、Invalidation対象のパスにクエリ文字列を含める必要があります。(クエリ文字列部分のワイルドカードの利用も可です。)Cookieやヘッダーをオリジンに転送している場合は対象となるパスのみを指定すれば良いため、混乱することがあるかもしれません。というか私が混乱してしまったので備忘録がてらまとめてみたいと思います。
CloudFrontでクエリ文字列をオリジンに転送している際のInvalidationについて確認してみた
Amazon CloudFront開発者ガイドを確認すると、その旨記載があります。
- ファイルの無効化 - Amazon CloudFront
- 「無効にするファイルの指定」 > 「クエリ文字列の転送」
以下では実際に、オリジンにクエリ文字列を転送するCloudFrontを構築、Invalidation時の挙動を確認してみました。
確認する環境について
オリジンはEC2にApache+PHPをインストールし、リクエスト時の時間とクエリ文字列を出力するコード(qs.php)を配置しました。コードは以下になります。
<?php date_default_timezone_set('Asia/Tokyo'); echo date("Y/m/d H:i:s"); echo "\n"; echo $_SERVER['QUERY_STRING'] ?>
実際にアクセスすると、以下のような出力となります。
$ curl "http://ec2-XXX-XXX-XXX-XXX.ap-northeast-1.compute.amazonaws.com/qs.php?foo=bar" 2020/05/31 10:55:48 foo=bar
このEC2をオリジンとして、CloudFrontディストリビューションを作成します。クエリ文字列をすべてオリジンに転送するよう設定し、またキャッシュTTLは1日(86400秒)となるよう設定します。
クエリ文字列含め、キャッシュされていることを確認する
上記の環境で、例えば以下のようにdateコマンド後にcurlコマンドを実行し、リクエスト時の時刻とレスポンスの内容に含まれる時刻が同じであれば、キャッシュが使われなかった状態(キャッシュミス)、異なる時間であればキャッシュが使われた状態(キャッシュヒット)状態、ということがわかります。
キャッシュが使われなかった状態
$ date; curl "https://d1234567890.cloudfront.net/qs.php?foo=bar" 2020年 5月31日 日曜日 10時59分25秒 JST 2020/05/31 10:59:25 foo=bar
キャッシュが使われた状態
$ date; curl "https://d1234567890.cloudfront.net/qs.php?foo=bar" 2020年 5月31日 日曜日 11時05分05秒 JST 2020/05/31 10:59:25 foo=bar
Invalidation(ファイルを無効化/キャッシュクリア)した場合、意図した通りにできてれば、次のアクセスではキャッシュが使われなかった状態になり、リクエスト時の時刻とレスポンスの内容に含まれる時刻が同じになるはずです。(コンマ数秒の時差で1秒は違いが出るかもしれませんが。)
準備として、いくつかのクエリ文字列をキャッシュさせておく
まずは準備として、いくつかのクエリ文字列に対して、以降のアクセスでキャッシュを使うよう、あらかじめアクセスしてキャッシュさせておきます。
$ date; curl "https://d1234567890.cloudfront.net/qs.php?foo=bar" 2020年 5月31日 日曜日 10時59分25秒 JST 2020/05/31 10:59:25 foo=bar $ date; curl "https://d1234567890.cloudfront.net/qs.php?foo=baz" 2020年 5月31日 日曜日 10時59分39秒 JST 2020/05/31 10:59:39 foo=baz $ date; curl "https://d1234567890.cloudfront.net/qs.php" 2020年 5月31日 日曜日 11時06分09秒 JST 2020/05/31 11:06:09 $ date; curl "https://d1234567890.cloudfront.net/qs.php?hoovers=ooover" 2020年 5月31日 日曜日 11時06分59秒 JST 2020/05/31 11:06:59 hoovers=ooover
クエリ文字列なしでInvalidationしてみる
まずはクエリ文字列なしでInvalidationしてみます。/qs.php
でInvalidationを実行します。
Invalidation完了後、確認してみましょう。クエリ文字列なしの場合は以下のようにキャッシュがクリアされました。(アクセス時にキャッシュが使われませんでした。)
$ date; curl "https://d1234567890.cloudfront.net/qs.php" 2020年 5月31日 日曜日 11時16分43秒 JST 2020/05/31 11:16:43
しかしクエリ文字列をつけたアクセスでは、下記のようにキャッシュが使われた状態となりました。ファイル無効化(Invalidation)の際はクエリ文字列を含める必要があるので、クエリ文字列を含めない場合は、クエリ文字列なしの場合しかInvalidationが行われない、ということですね。
$ date; curl "https://d1234567890.cloudfront.net/qs.php?foo=bar" 2020年 5月31日 日曜日 11時24分36秒 JST 2020/05/31 10:59:25 foo=bar $ date; curl "https://d1234567890.cloudfront.net/qs.php?foo=baz" 2020年 5月31日 日曜日 11時24分39秒 JST 2020/05/31 10:59:39 foo=baz
クエリ文字列を指定してInvalidationしてみる
続いてクエリ文字列部分を指定してInvalidationをしてみましょう。/qs.php?foo=bar
でInvalidationを実行します。
Invalidation完了後、確認します。以下のようにInvalidation対象としたクエリ文字列についてはキャッシュクリアされていることが確認できます。
$ date; curl "https://d1234567890.cloudfront.net/qs.php?foo=bar" 2020年 5月31日 日曜日 11時27分37秒 JST 2020/05/31 11:27:37 foo=bar
クエリ文字列のうち、そのkeyは同じでもvalue部分が異なるリクエスト、/qs.php?foo=baz
についてはInvalidation対象でなかったため、キャッシュクリアされておらず、キャッシュが利用されている状態です。
[shimizu.toshiya@classmethod] [~] $ date; curl "https://d1234567890.cloudfront.net/qs.php?foo=baz" 2020年 5月31日 日曜日 11時28分45秒 JST 2020/05/31 10:59:39 foo=baz
keyもvalueも異なるリクエストについても同様、キャッシュクリアされていません。
$ date; curl "https://d1234567890.cloudfront.net/qs.php?hoovers=ooover" 2020年 5月31日 日曜日 11時29分47秒 JST 2020/05/31 11:06:59 hoovers=ooover
クエリ文字列なしのリクエストについても、同じくキャッシュクリアされていません。
$ date; curl "https://d1234567890.cloudfront.net/qs.php" 2020年 5月31日 日曜日 11時30分16秒 JST 2020/05/31 11:16:43
クエリ文字列にワイルドカード「*」を使ってInvalidationしてみる
クエリ文字列を含めたInvalidationを行う際に、そのクエリ文字列部分にもワイルドカードを利用することができます。/qs.php?fo*
でInvalidationしてみます。
fo
から始まるクエリ文字列がキャッシュクリアされました。
$ date; curl "https://d1234567890.cloudfront.net/qs.php?foo=bar" 2020年 5月31日 日曜日 11時36分49秒 JST 2020/05/31 11:36:49 foo=bar $ date; curl "https://d1234567890.cloudfront.net/qs.php?foo=baz" 2020年 5月31日 日曜日 11時36分53秒 JST 2020/05/31 11:36:53 foo=baz
もちろん、クエリ文字列部分がfo*
にマッチしないパスについては、キャッシュクリアされていません。
$ date; curl "https://d1234567890.cloudfront.net/qs.php?hoovers=ooover" 2020年 5月31日 日曜日 11時38分09秒 JST 2020/05/31 11:06:59 hoovers=ooover $ date; curl "https://d1234567890.cloudfront.net/qs.php" 2020年 5月31日 日曜日 11時38分12秒 JST 2020/05/31 11:16:43
ファイル名+ワイルドカード「*」でInvalidationしてみる
同じファイル(今回ならqs.php
)に対するすべてのクエリ文字列に対してInvalidationを行いたい場合には、qs.php*
のようにファイル名の後にワイルドカード*
を付与することで実現できます。
Invalidation完了後、確認してみると以下のように、qs.php
へのアクセスでクエリ文字列に関わらずキャッシュクリアされていることがわかります。
$ date; curl "https://d1234567890.cloudfront.net/qs.php?foo=bar" 2020年 5月31日 日曜日 11時41分56秒 JST 2020/05/31 11:41:56 foo=bar $ date; curl "https://d1234567890.cloudfront.net/qs.php?foo=baz" 2020年 5月31日 日曜日 11時42分06秒 JST 2020/05/31 11:42:06 foo=baz $ date; curl "https://d1234567890.cloudfront.net/qs.php?hoovers=ooover" 2020年 5月31日 日曜日 11時42分12秒 JST 2020/05/31 11:42:12 hoovers=ooover $ date; curl "https://d1234567890.cloudfront.net/qs.php" 2020年 5月31日 日曜日 11時42分18秒 JST 2020/05/31 11:42:18
まとめ
Amazon CloudFrontでクエリ文字列オリジンに転送しているよう設定している場合、Invalidation(ファイル無効化)の際にはクエリ文字列部分も含めて指定が必要であることを確認してみました。オリジンへの転送項目となる他の2項目、Cookieとヘッダーについては対象パスについて一括でInvalidationされるので私は少しこんがらがってしまっていましたが、クエリ文字列についてはURLの一部でもあるので、ブラウザなどで確認できるURLをInvalidationの際にパスとして指定する、と把握しておけば忘れにくいかもしれません。