キャッシュヒット率の最大化

ストアフロントのパフォーマンスを向上させる最善の方法の 1 つとして、キャッシュヒット率の最大化があげられます。Managed Runtime の CDN キャッシュから応答できるすべてのリクエストは、キャッシュヒットとしてカウントされます。キャッシュヒットが発生するたびに、そのページをサーバー側でレンダリングしてバックエンドシステムと API にリクエストするコストを節約できるため、ユーザーのページの読み込みがスピードアップします。

このガイドでは、キャッシュヒットを最大化するために、キャッシュライフタイムの最適な設定、条件付きレンダリング、およびクエリ文字列のフィルターという 3 つの異なる手法を説明します。それぞれの手法を詳しく見てみましょう。

HTTP リクエストをキャッシュする最適な時間は、リクエストの内容によって異なります。あまり変更が行われないコンテンツページを読み込むリクエストは、長期間キャッシュしても安全です。反対に、新商品で頻繁に更新される商品一覧ページは、たとえば 15 分などの、短いキャッシュライフタイムが必要な場合があります。可能であれば、キャッシュヒット率を最大にするために長いキャッシュライフタイムを選ぶようにしてください。

HTTP レスポンスの cache-control ヘッダーによって、ページリクエストへのレスポンスが CDN キャッシュに保管される期間が決まります。PWA Kit プロジェクトにおけるページレスポンスのキャッシュライフタイムは、デフォルトでは 600 秒 (10 分) です。キャッシュライフタイムはページごとに、またはすべてのページに対してカスタマイズできます。

キャッシング全般の詳細については、Google による記事の HTTPキャッシュを使用して不要なネットワーク要求を防ぐをお勧めします。

任意のページコンポーネントの getProps 関数では、呼び出された res で渡されるオブジェクトを使用して HTTP レスポンスをカスタマイズできます。ページのキャッシュライフタイムを設定するには、res オブジェクトの set メソッドを使用して Cache-Control ヘッダーを設定し、max-age ディレクティブの値を秒単位で指定します。

たとえば、以下の ProductList コンポーネントはキャッシュのライフタイムをデフォルトの 600 秒から 900 秒に延長します:

cache-control ヘッダーを、app/components/_app/index.jsx で定義される App 特殊コンポーネントに属する getProps 関数の内部で設定することはお勧めしません。App コンポーネントと現在のページコンポーネントの両方の getProps 関数は、同時に実行されます。同じレスポンスヘッダーを両方の関数で設定した場合、この並行実行によって予想外の結果が生じる場合があります。

すべてのページのキャッシュライフタイムを app/ssr.js で設定できます。defaultCacheTimeSeconds に新しい値を設定することで、デフォルトのキャッシュライフタイムを変更できます。HTTP ヘッダーに関してより細かいコントロールが必要な場合は、以下のようにカスタムヘッダーを設定する Express ハンドラーを追加します:

レスポンスヘッダーにキャッシュコントロールがあることをテストするには、Chrome の DevTools の Network (ネットワーク) タブでネットワークリクエストを確認します。または、ターミナルで以下の curl コマンドを実行すると、すべてのレスポンスヘッダーが出力されます。このコマンドの例の <URL> を、テストしたい完全な URL (すべてのクエリ文字列を含む) で置き換えます。

ページが CDN によるキャッシュに適していることを確実にするために、サーバー側の以下のタイプのコンテンツがレンダリングされないように条件コードを追加する必要があります:

  • パーソナル化されたコンテンツ: ユーザー名、買い物カゴ内の商品数、好みの支払方法など。パーソナル化されたコンテンツは、特定のユーザー以外に対しては適しておらず、関連性ももちません。特定のユーザーに対するレスポンスをキャッシュしても、キャッシュのヒットは向上されません。
  • 頻繁に変更されるコンテンツ: 商品の価格、残りの在庫、セールスプロモーションなど。古くなった情報がページに含まれるとユーザーが混乱する可能性があるため、これらのコンテンツはキャッシュには適していません。

サーバー側でレンダリングされるページは、クライアントのための一般的な基礎情報だと考えてください。サーバー側のバージョンのページをユーザーのデバイスにすばやく読み込んだ後に、ブラウザーが、パーソナル化されたコンテンツと頻繁に変更されるコンテンツのレンダリングを行います。

レンダリングがクライアント側とサーバー側のどちらで行われるかを見極めるには、window オブジェクトがあるかどうかを確認します。このオブジェクトはクライアント側にのみあります。以下の例では、この手法を使用してクライアント側のみで価格をレンダリングします。

サーバー側でレンダリングされるページのバージョンをブラウザーでプレビューするには、URL の最後に ?__server_only を追加します。このクエリパラメーターは ハイドレーション プロセスを停止するため、ブラウザーはレンダリングを行わず、サーバー側のレンダリング後にページが変更されません。

ほとんどのストアフロントアプリでは、URL のクエリ文字列を使用してアプリの状態のさまざまな面を表すパラメーターと値を保管します。たとえば、ユーザーが「sweaters」を検索した場合、この検索用語をクエリ文字列に ?search=sweaters のように含めることができます。また、クエリ文字列はユーザーのアクションを追跡するためにも一般的に使用されます。たとえば、Eメールでのインタラクションを追跡するために、Eメール内の各リンクの最後に一意のクエリ文字列を user=juanita&source=email のように追加できます。

キャッシュでは、すべてのクエリ文字列パラメーターが関連性をもつわけではありません。Managed Runtime にはリクエストプロセッサーというエッジ関数があり、キャッシュされたレスポンスが検索される前に、リクエストのクエリ文字列を変更できます。このリクエストプロセッサーを使用して、類似の URL を同一のキャッシュされたレスポンスにマッピングすることで、キャッシュのヒットを向上できます。

リクエストプロセッサーをカスタマイズするには、app/request-processor.js で定義されている processRequest 関数を編集します。

以下の例は、クエリ文字列からパラメーター gclidutm_campaign をフィルターするリクエストプロセッサーを定義しています。これらのパラメーターは通常 Google マーケティングキャンペーンと関連付けられたもので、クライアント側でのみ有用です。クエリ文字列での作業を簡易化するために、PWA Kit React SDK から QueryParameters クラスがインポートされます。

対応するオブジェクトをキャッシュで検索するために使用される完全な URL には、リクエストプロセッサーから返されたクエリ文字列のバージョンが含まれます。この URL へのレスポンスがキャッシュされていない場合は、同一の修正バージョンの URL が Express アプリに渡されます。

このアプローチを使用する場合は、以下の 2 つの点に注意してください:

まず、アプリでのレンダリングが、フィルターされるパラメーターに依存していないことを確認します。たとえば、上記で search パラメーターをフィルターすると、正しい検索結果を表示する際に問題が発生します。

次に、リダイレクトが予想されるリクエストからパラメーターをフィルターする際には注意してください。フィルターされるパラメーターにコードがアクセスできないと、そのパラメーターはリダイレクトにも使用できません。www.example.com?lang=en のリクエストを www.example.com/en などの地域情報固有のパスにリダイレクトするホームページコンポーネントのリクエストを考えてみましょう。lang パラメーターをフィルターすると、正しい地域情報にリダイレクトできません。

以下の例を順に見てみましょう:

  1. リクエストプロセッサーが www.example.com/?gclid=123 のリクエストを処理します。
  2. リクエストプロセッサーが gclid クエリ文字列パラメーターをフィルターします。
  3. リクエストは、完全な URL www.example.com でアプリケーションに転送されます。
  4. アプリケーションが www.example.com/en へのリダイレクトを返します。

この最後のステップで、元の gclid パラメーターが失われたことに注意してください。このため、ユーザーがリダイレクトされた後に、ブラウザーでこのパラメーターを使用できません。この問題を回避するために、リダイレクトが予想されるリクエストではクエリ文字列のフィルターを避けてください。

これで、さまざまな手法を使用してページのキャッシュヒットを向上させる方法を学習しました。

API リクエストのキャッシングやその他のプロキシの利点の詳細については、リクエストのプロキシのガイドを参照してください。