しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

Azure Front Door と Static Web Apps の組み合わせでの最適なキャッシュ設定を探った

Static Web Apps を使って SPA アプリケーションをデプロイして運用していると、現状の Static Web Apps のリージョンが一番近くて East Asia になり日本からはレイテンシがそこそこ大きいので、Front Door を導入して全体的なパフォーマンスを改善したくなります。

特に最近のフレームワークはバンドルされるので、ファイル名がハッシュベースでユニークなものになるためキャッシュさせやすいです。今回は Nuxt 4 を使って Front Door での適切なキャッシュ設定を確認しました。

Nuxt 4 はビルドを行うと以下のように _nuxt ディレクトリ以下にバンドルされたファイルが入るので、このディレクトリ以下をキャッシュすると効果が出ます。それ以外の index.html などのファイルはキャッシュすると問題になるので無効化する必要があります。

バンドルされたファイル名にはハッシュベースでユニークなものが入るので、それぞれを Immutable なものとして扱えるためキャッシュしやすいのがメリットです。

これから実際に Static Web Apps と Front Door に設定を追加して、キャッシュを有効化していきます。

Static Web Apps で適切な Cache-Control を返す

ファイルやディレクトリ単位での柔軟なキャッシュを行うために Cache-Control を返す設定を SWA の設定ファイル staticwebapp.config.json に追加します。

設定方法としてはルート単位での追加と、グローバルでの追加があるので、上手く組み合わせて実現します。今回は以下のように _nuxt ディレクトリ以下はキャッシュを長時間行うように設定しますが、それ以外はキャッシュしないように設定を追加します。

{
  "$schema": "https://www.schemastore.org/staticwebapp.config.json",
  "routes": [
    {
      "route": "/_nuxt/*",
      "headers": {
        "Cache-Control": "max-age=31536000, immutable"
      }
    }
  ],
  "globalHeaders": {
    "Cache-Control": "no-store"
  }
}

この設定を含めてデプロイを行うと _nuxt ディレクトリ以下のファイルはキャッシュが有効となり、それ以外のファイルはキャッシュが無効なヘッダーが返るようになります。

API で適切な Cache-Control を返す

Static Web Apps の特徴となるバックエンド API をホストする機能ですが、その対象となる /api パス以下には staticwebapp.config.json でのヘッダー設定は反映されません。そのため API 側で適切に Cache-Control ヘッダーを返す必要があります。

Azure Functions の場合は host.json にカスタムヘッダーを設定があるので、それを使うと簡単に独自のヘッダーを返すことが出来ます。

{
  "version": "2.0",
  "extensions": {
    "http": {
      "routePrefix": "api",
      "customHeaders": {
        "Cache-Control": "no-store"
      }
    }
  }
}

基本的には API はキャッシュを行わないので、上のような設定を使ってグローバルに適用してしまって問題ないはずです。API 単位で細かいキャッシュ設定が必要な場合には、フレームワーク側に機能があるはずなので柔軟に対応できるはずです。

Front Door のキャッシュを有効化する

ここまでの設定で Static Web Apps レベルでは一通り適切なキャッシュ設定が行えたはずなので、後は Front Door 側でキャッシュ設定を有効化するだけとなります。

キャッシュの設定はルート単位で行うので、SWA 側で行っていた設定を Front Door で行うことも出来ましたが、管理性が悪いので Front Door 側でキャッシュのために複雑な構成を行うのは避けた方が無難です。

実際の設定としては以下ぐらいで問題ありません。クエリ文字列をキャッシュキーに含めるかどうかは要検討ですが、Nuxt 4 の場合はファイルにハッシュが含まれているので無視して問題ありません。

Front Door でキャッシュを有効化すると圧縮が利用可能になるので、キャッシュと同時に圧縮も有効化しておくと転送サイズが小さくなるのでより効率的になります。

この設定で Static Web Apps でホストしている Nuxt 4 アプリケーションのアセットは Front Door で適切にキャッシュされるようになりますが、Static Web Apps が Cache-Control を返さないケースがあれば 1-3 日の間でランダムにキャッシュされてしまうので、意図しない挙動となる可能性が高いです。

If the Cache-Control header isn't present on the response from the origin, by default Front Door randomly determines a cache duration between one and three days.

Caching with Azure Front Door | Microsoft Learn

基本的にはここまでの設定で全ての Static Web Apps からの応答には Cache-Control が付くはずですが、稀に SWA の障害などで壊れた応答が返ることがあるようです。その場合には応答に Cache-Control が含まれないため Front Door で長時間キャッシュされてしまいます。

かなりレアケースにはなるのですが、この問題を避けるために Front Door のルールセットで Cache-Control が付いていない場合にはキャッシュ設定をオーバーライドして回避します。

ルールセットのキャッシュのビヘイビアで Override if origin missing を選ぶと、キャッシュ設定が無い場合のオーバーライドが可能です。具体的には以下のようなルールセットを用意することで、キャッシュ設定が無い場合には 1 秒だけキャッシュするようにします。

本来であればキャッシュ自体を無効化したいのですが、0 秒に設定した場合には無効化とはならず設定自体が無視されるので、今回は 1 秒を設定して回避しています。SWA の障害発生時というレアケース向けの設定なので、このような設定でも問題にはならないと考えています。

キャッシュが意図した通りに行われているか確認

一通り設定が完了したので実際に Front Door のエンドポイント経由でアクセスして、キャッシュが行われているかを確認します。Front Door は X-Cache ヘッダーでキャッシュの状態を返してくれるので、この値を見るとキャッシュが行われているか確認出来ます。

ルートにアクセスすると index.html が返るのでキャッシュが無効になっています。

次に _nuxt ディレクトリ以下のファイルではキャッシュにヒットしていることが確認出来ます。

以前に比べて Front Door のキャッシュパージは高速化されていますが、意図しないキャッシュが行われてしまうと大きな問題となるため、まずは TTL は短めから徐々に伸ばしていくのがベストでしょう。全てのリクエストに対して Cache-Control を適切に返すというのも重要になります。