キャッシング
導入
キャッシングは、以前にダウンロードしたコンテンツの再利用を可能にする手法です。コストのかかるネットワークリクエストを回避することにより、パフォーマンスが大幅に向上します。また、Webサイトのオリジンインフラストラクチャへのトラフィックを削減することで、アプリケーションの拡張にも役立ちます。「最速のリクエストはあなたがする必要のないものです」という古い格言があり、キャッシュはリクエストを行わなくて済むようにするための重要な方法の1つです。
Webコンテンツのキャッシュには、3つの基本原則があります。可能な限りキャッシュする、できる限りキャッシュする、エンドユーザーのできるだけ近くでキャッシュする。
可能な限りキャッシュする。 キャッシュできる量を検討する場合、レスポンスが静的か動的かを理解することが重要です。静的なレスポンスとして提供される要求は、リソースとそれを要求するユーザーとの間に1対多の関係があるため、通常はキャッシュ可能です。動的に生成されたコンテンツはより微妙である可能性があり、慎重に検討する必要があります。
できるだけ長くキャッシュする。リソースをキャッシュする時間の長さは、キャッシュされるコンテンツの機密性に大きく依存します。バージョン管理されたJavaScriptリソースは非常に長い時間キャッシュされる可能性がありますが、バージョン管理されていないリソースはユーザーが最新バージョンを取得できるように、より短いキャッシュ期間を必要とする場合があります。
エンドユーザーのできるだけ近くでキャッシュする。エンドユーザーの近くでコンテンツをキャッシュすると、待ち時間がなくなり、ダウンロード時間が短縮されます。たとえば、リソースがエンドユーザーのブラウザにキャッシュされている場合、リクエストはネットワークに送信されず、ダウンロード時間はマシンのI/Oと同じくらい高速です。初めての訪問者、またはキャッシュにエントリがない訪問者の場合、通常、キャッシュされたリソースが返される場所はCDNになります。ほとんどの場合、オリジンサーバーと比較して、ローカルキャッシュかCDNからリソースをフェッチする方が高速です。
通常、Webアーキテクチャには複数のキャッシュ層が含まれます。たとえば、HTTPリクエストは次の場所にキャッシュされる可能性があります。
- エンドユーザーのブラウザ
- ユーザーのブラウザーのService Workerキャッシュ
- 共有ゲートウェイ
- エンドユーザーに近い側でキャッシュする機能を提供するCDN
- バックエンドの仕事長を削減するための、アプリケーションの前のキャッシングプロキシ
- アプリケーション層とデータベース層
この章では、Webブラウザー内でリソースがキャッシュされる方法について見ていきましょう。
HTTPキャッシングの概要
HTTPクライアントがリソースをキャッシュするには、2つの情報を理解する必要があります。
- 「これをキャッシュできる期間はどれくらいですか?」
- 「コンテンツがまだ新しいことを検証するにはどうすればよいですか?」
Webブラウザーがクライアントにレスポンスを送信するとき、通常リソースにキャッシュ可能か、キャッシュする期間、リソースの古さを示すヘッダーが含まれます。 RFC 7234は、これをセクション4.2(新しさ)および4.3(検証)でより詳細にカバーしています。
通常、有効期間を伝えるために使用されるHTTPレスポンスヘッダーは次のとおりです。
Cache-Control
キャッシュの生存期間(つまり、有効期間)を設定できます。Expires
有効期限の日付または時刻を提供します(つまり、期限切れになるとき)。
Cache-Control
両方が存在する場合に優先されます。これらについては、以下で詳しく説明します。
キャッシュ内に保存された応答を検証するためのHTTPレスポンスヘッダー、つまりサーバー側で比較するため、条件付き要求を提供するHTTPレスポンスヘッダーは次のとおりです。
Last-Modified
オブジェクトが最後に変更された日時を示します。- エンティティタグ (
ETag
) コンテンツの一意の識別子を提供します。
ETag
両方が存在する場合に優先されます。これらについては、以下で詳しく説明します。
以下の例には、HTTP Archiveのmain.jsファイルからのリクエスト/レスポンスヘッダーの抜粋が含まれています。これらのヘッダーは、リソースを43,200秒(12時間)キャッシュでき、最後は2か月以上前に変更されたことを示します(Last-Modified
ヘッダーとDate
ヘッダーの違い)。
> GET /static/js/main.js HTTP/1.1
> Host: httparchive.org
> User-agent: curl/7.54.0
> Accept: */*
< HTTP/1.1 200
< Date: Sun, 13 Oct 2019 19:36:57 GMT
< Content-Type: application/javascript; charset=utf-8
< Content-Length: 3052
< Vary: Accept-Encoding
< Server: gunicorn/19.7.1
< Last-Modified: Sun, 25 Aug 2019 16:00:30 GMT
< Cache-Control: public, max-age=43200
< Expires: Mon, 14 Oct 2019 07:36:57 GMT
< ETag: "1566748830.0-3052-3932359948"
RedBot.orgというツールにURLを入力すると、レスポンスのヘッダーを元としたキャッシュ方法の詳細な説明が表示できます。たとえば、上記のURLのテストは次のような内容を出力します。
レスポンスにキャッシュヘッダーが存在しない場合、クライアントはレスポンスをヒューリスティクスにキャッシュできます。ほとんどのクライアントは、RFCの推奨ヒューリスティックバリエーションを実装します。これは、Last-Modified
から経過した時間の10%です。ただし、レスポンスを無期限にキャッシュする可能性もあります。そのため、特定のキャッシュルールを設定して、キャッシュ可能性を確実に制御することが重要です。
レスポンスの72%はCache-Control
ヘッダーで提供され、レスポンスの56%はExpires
ヘッダーで提供されます。ただし、レスポンスの27%はどちらのヘッダーも使用していないため、ヒューリスティックキャッシュの対象となります。これは、デスクトップとモバイルサイトの両方で一貫しています。
キャッシュするコンテンツの種類は何ですか?
キャッシュ可能なリソースは、クライアントによって一定期間保存され、後続のリクエストで再利用できます。すべてのHTTPリクエスト全体で、レスポンスの80%はキャッシュ可能と見なされます。つまり、キャッシュがそれらを格納することを許可されています。
- 要求の6%のTime To Time(TTL)は0秒で、キャッシュされたエントリはすぐに無効になります。
- 27%は
Cache-Control
ヘッダーがないため、ヒューリスティックにキャッシュされます。 - 47%は0秒以上キャッシュされます。
残りのレスポンスは、ブラウザーのキャッシュに保存できません。
次の表は、デスクトップリクエストのキャッシュTTL値をタイプ別に詳細に示しています。ほとんどのコンテンツタイプはキャッシュされますが、CSSリソースは高いTTLで一貫してキャッシュされるようです。
デスクトップキャッシュTTLパーセンタイル(時間) | |||||
---|---|---|---|---|---|
10 | 25 | 50 | 75 | 90 | |
Audio | 12 | 24 | 720 | 8,760 | 8,760 |
CSS | 720 | 8,760 | 8,760 | 8,760 | 8,760 |
Font | < 1 | 3 | 336 | 8,760 | 87,600 |
HTML | < 1 | 168 | 720 | 8,760 | 8,766 |
Image | < 1 | 1 | 28 | 48 | 8,760 |
Other | < 1 | 2 | 336 | 8,760 | 8,760 |
Script | < 1 | < 1 | 1 | 6 | 720 |
Text | 21 | 336 | 7,902 | 8,357 | 8,740 |
Video | < 1 | 4 | 24 | 24 | 336 |
XML | < 1 | < 1 | < 1 | < 1 | < 1 |
TTLの中央値のほとんどは高いですが、低いパーセンタイルは、見逃されたキャッシングの機会の一部を強調しています。たとえば画像のTTLの中央値は28時間ですが、25パーセンタイルは1〜2時間であり、10パーセンタイルはキャッシュ可能な画像コンテンツの10%が1時間未満キャッシュされることを示します。
以下の図16.5でコンテンツタイプごとのキャッシュ可能性を詳細に調べると、すべてのHTMLレスポンスの約半分がキャッシュ不可と見なされていることがわかります。さらに、画像とスクリプトの16%はキャッシュ不可です。
モバイルの同じデータを以下に示します。ご覧のとおり、コンテンツタイプのキャッシュ可能性はデスクトップとモバイルで一貫しています。
Cache-Control
とExpires
HTTP/1.0では、Expires
ヘッダーは、レスポンスが古くなったと見なされる日時を示すために使用されました。その値は、次のような日付のタイムスタンプです。
Expires: Thu, 01 Dec 1994 16:00:00 GMT
HTTP/1.1はCache-Control
ヘッダーを導入し、最新のクライアントのほとんどは両方のヘッダーをサポートしています。このヘッダーは、キャッシングディレクティブを介して、はるかに高い拡張性を提供します。例えば。
no-store
リソースをキャッシュしないことを示すために使用できます。max-age
鮮度の寿命を示すために使用できます。must-revalidate
キャッシュされたエントリは、使用する前に条件付きリクエストで検証する必要があることをクライアントに伝えます。private
レスポンスはブラウザによってのみキャッシュされ、複数のクライアントにサービスを提供する仲介者によってキャッシュされるべきではないことを示します。
HTTPレスポンスの53%は、max-age
ディレクティブを持つCache-Control
ヘッダーが含まれ、54%はExpiresヘッダーが含まれます。ただし、これらのレスポンスの41%のみが両方のヘッダーを使用します。つまり、レスポンスの13%が古いExpires
ヘッダーのみに基づいてキャッシュされます。
Cache-Control
ディレクティブ
HTTP/1.1仕様には、Cache-Control
レスポンスヘッダーで使用できる複数のディレクティブが含まれており、以下で詳しく説明します。1つのレスポンスで複数を使用できることに注意してください。
ディレクティブ | 説明 |
---|---|
max-age | リソースをキャッシュできる秒数を示します。 |
public | 任意のキャッシュにレスポンスを保存できます。 |
no-cache | キャッシュされたエントリは、使用する前に再検証する必要があります。 |
must-revalidate | 古いキャッシュエントリは、使用する前に再検証する必要があります。 |
no-store | レスポンスがキャッシュ不可能なことを示します。 |
private | レスポンスは特定のユーザー向けであり、共有キャッシュに保存しない。 |
no-transform | このリソースに対して変換を行わないでください。 |
proxy-revalidate | must-revalidateと同じですが、共有キャッシュに適用されます。 |
s-maxage | max ageと同じですが、共有キャッシュにのみ適用されます。 |
immutable | キャッシュされたエントリは決して変更されず、再検証は不要であることを示します。 |
stale-while-revalidate | クライアントがバックグラウンドで新しいレスポンスを非同期にチェックしながら、古いレスポンスを受け入れようとしていることを示します。 |
stale-if-error | 新しいレスポンスのチェックが失敗した場合に、クライアントが古いレスポンスを受け入れる意思があることを示します。 |
Cache-Control
ディレクティブ。
たとえば、cache-control:public、max-age = 43200
は、キャッシュされたエントリを43,200秒間保存し、共有キャッシュに保存できることを示します。
上記の図16.9は、モバイルWebサイトで使用されている上位15のCache-Control
ディレクティブを示しています。デスクトップとモバイルの結果は非常に似ています。これらのキャッシュディレクティブの人気について、興味深い観察結果がいくつかあります。
max-age
はCache-Control
ヘッダーのほぼ75%で使用され、no-store
は18%で使用されます。private
が指定されない限り、キャッシュされたエントリはpublic
であると想定されるため、public
が必要になることはほとんどありません。回答の約38%にpublic
が含まれています。immutable
ディレクティブは比較的新しく、2017年に導入され、FirefoxおよびSafariでサポートされています。その使用率は3.4%に拡大し、Facebook、Googleのサードパーティのレスポンスで広く使用されています。
このリストに表示される別の興味深いディレクティブセットは、pre-check
とpost-check
です。これらは、Cache-Control
レスポンスヘッダーの2.2%(約780万件のレスポンス)で使用されます。このヘッダーのペアは、バックグラウンドで検証を提供するためにInternet Explorer 5で導入されたものですが、Webサイトによって正しく実装されることはほとんどありませんでした。これらのヘッダーを使用したレスポンスの99.2%は、pre-check=0
とpost-check=0
の組み合わせを使用していました。これらのディレクティブの両方が0に設定されている場合、両方のディレクティブは無視されます。したがって、これらのディレクティブは正しく使用されなかったようです!
ロングテールでは、レスポンスの0.28%で1,500を超える間違ったディレクティブが使用されています。これらはクライアントによって無視され、「nocache」「s-max-age」「smax-age」「maxage」などのスペルミスが含まれます。「max-stale」「proxy-public」「surrogate-control」など存在しないディレクティブも多数あります。
Cache-Control
: no-store
, no-cache
and max-age=0
レスポンスがキャッシュ可能でない場合、Cache-Control
no-store
ディレクティブを使用する必要があります。このディレクティブを使用しない場合、レスポンスはキャッシュ可能です。
レスポンスをキャッシュ不可に設定しようとすると、いくつかの一般的なエラーが発生します。
Cache-Control: no-cache
の設定は、リソースがキャッシュできないように聞こえるかもしれません。ただし、no-cache
ディレクティブでは、使用する前にキャッシュされたエントリを再検証する必要があり、キャッシュ不可と同じではありません。Cache-Control: max-age = 0
を設定すると、TTLが0秒に設定されますが、これはキャッシュ不可と同じではありません。 max-ageを0に設定すると、リソースはブラウザーのキャッシュに保存され、すぐに無効になります。これにより、ブラウザは条件付きリクエストを実行してリソースの新しさを検証する必要があります。
機能的には、no-cache
とmax-age=0
は似ています。どちらもキャッシュされたリソースの再検証を必要とするためです。 no-cache
ディレクティブは、0より大きいmax-age
ディレクティブと一緒に使用することもできます。
300万を超えるレスポンスには、no-store
、no-cache
、max-age=0
の組み合わせが含まれます。これらのディレクティブのうち、no-store
が優先され、他のディレクティブは単に冗長です。
レスポンスの18%にはno-store
が含まれ、レスポンスの16.6%にはno-store
とno-cache
の両方が含まれます。no-store
が優先されるため、リソースは最終的にキャッシュ不可になります。
max-age=0
ディレクティブは、no-store
が存在しないレスポンスの1.1%(400万を超えるレスポンス)に存在します。これらのリソースはブラウザにキャッシュされますが、すぐに期限切れになるため、再検証が必要になります。
キャッシュTTLとリソースの経過時間はどのように比較されますか?
これまで、Webサーバーがキャッシュ可能なものをクライアントに通知する方法と、キャッシュされる期間について説明してきました。キャッシュルールを設計するときは、提供しているコンテンツの古さを理解することも重要です。
キャッシュTTLを選択するときは、「これらのアセットをどのくらいの頻度で更新しますか?」と自問してください。そして「彼らのコンテンツの感度は何ですか?」。たとえば、ヒーローのイメージがたまに更新される場合、非常に長いTTLでキャッシュします。 JavaScriptリソースが頻繁に変更されることが予想される場合は、バージョン管理して長いTTLでキャッシュするか、短いTTLでキャッシュします。
以下のグラフは、コンテンツタイプごとのリソースの相対的な年を示しています。ここで、より詳細な分析を読むことができます。 HTMLは最も短い年齢のコンテンツタイプである傾向があり、伝統的にキャッシュ可能なリソース(スクリプト、CSS、およびフォント)の非常に大きな割合が1年以上古いです!
リソースのキャッシュ可能性をその経過時間と比較することにより、TTLが適切であるか短すぎるかを判断できます。たとえば、以下のレスポンスによって提供されるリソースは、2019年8月25日に最後の変更がされました。つまり、配信時に49日経過していました。 Cache-Control
ヘッダーは、43,200秒(12時間)キャッシュできることを示しています。より長いTTLが適切かどうかを調査するのに十分古いものです。
< HTTP/1.1 200
< Date: Sun, 13 Oct 2019 19:36:57 GMT
< Content-Type: application/javascript; charset=utf-8
< Content-Length: 3052
< Vary: Accept-Encoding
< Server: gunicorn/19.7.1
< Last-Modified: Sun, 25 Aug 2019 16:00:30 GMT
< Cache-Control: public, max-age=43200
< Expires: Mon, 14 Oct 2019 07:36:57 GMT
< ETag: "1566748830.0-3052-3932359948"
全体的に、Webで提供されるリソースの59%のキャッシュTTLは、コンテンツの年齢に比べて短すぎます。さらに、TTLと経過時間のデルタの中央値は25日です。
これをファーストパーティとサードパーティで分けると、ファーストパーティのリソースの70%がより長いTTLの恩恵を受けることもわかります。これは、キャッシュ可能なものに特に注意を払い、キャッシュが正しく構成されていることを確認する必要があることを明確に強調しています。
クライアント | ファーストパーティ | サードパーティ | 全体 |
---|---|---|---|
デスクトップ | 70.7% | 47.9% | 59.2% |
モバイル | 71.4% | 46.8% | 59.6% |
鮮度の検証
キャッシュ内に格納されたレスポンスの検証に使用されるHTTPレスポンスヘッダーは、Last-Modified
およびETag
です。 Last-Modified
ヘッダーは、その名前が示すとおりに機能し、オブジェクトが最後に変更された時刻を提供します。 ETag
ヘッダーは、コンテンツの一意の識別子を提供します。
たとえば、以下のレスポンスは2019年8月25日に変更され、「1566748830.0-3052-3932359948」
のETag
値があります。
< HTTP/1.1 200
< Date: Sun, 13 Oct 2019 19:36:57 GMT
< Content-Type: application/javascript; charset=utf-8
< Content-Length: 3052
< Vary: Accept-Encoding
< Server: gunicorn/19.7.1
< Last-Modified: Sun, 25 Aug 2019 16:00:30 GMT
< Cache-Control: public, max-age=43200
< Expires: Mon, 14 Oct 2019 07:36:57 GMT
< ETag: "1566748830.0-3052-3932359948"
クライアントは、If-Modified-Since
という名前のリクエストヘッダーのLast-Modified
値を使用して、キャッシュされたエントリを検証する条件付きリクエストを送信できます。同様に、If-None-Match
リクエストヘッダーを使用してリソースを検証することもできます。これは、クライアントがキャッシュ内のリソースに対して持っているETag
値に対して検証します。
以下の例では、キャッシュエントリはまだ有効であり、HTTP 304
がコンテンツなしで返されました。これにより、リソース自体のダウンロードが保存されます。キャッシュエントリが最新ではない場合、サーバーは200
で更新されたリソースを応答し、再度ダウンロードする必要があります。
> GET /static/js/main.js HTTP/1.1
> Host: www.httparchive.org
> User-Agent: curl/7.54.0
> Accept: */*
> If-Modified-Since: Sun, 25 Aug 2019 16:00:30 GMT
< HTTP/1.1 304
< Date: Thu, 17 Oct 2019 02:31:08 GMT
< Server: gunicorn/19.7.1
< Cache-Control: public, max-age=43200
< Expires: Thu, 17 Oct 2019 14:31:08 GMT
< ETag: "1566748830.0-3052-3932359948"
< Accept-Ranges: bytes
全体としてレスポンスの65%はLast-Modified
ヘッダーで、42%はETag
で提供され、38%は両方を使用します。ただし、レスポンスの30%にはLast-Modified
ヘッダー、ETag
ヘッダーは含まれていません。
日付文字列の有効性
タイムスタンプの伝達に使用されるHTTPヘッダーがいくつかあり、これらの形式は非常に重要です。 Date
レスポンスヘッダーは、リソースがいつクライアントに提供されたかを示します。 Last-Modified
レスポンスヘッダーは、サーバーでリソースが最後に変更された日時を示します。また、Expires
ヘッダーは、(Cache-Control
ヘッダーの存在しない場合)リソースがキャッシュ可能な期間を示すために使用されます。
これら3つのHTTPヘッダーはすべて、日付形式の文字列を使用してタイムスタンプを表します。
例えば。
> GET /static/js/main.js HTTP/1.1
> Host: httparchive.org
> User-Agent: curl/7.54.0
> Accept: */*
< HTTP/1.1 200
< Date: Sun, 13 Oct 2019 19:36:57 GMT
< Content-Type: application/javascript; charset=utf-8
< Content-Length: 3052
< Vary: Accept-Encoding
< Server: gunicorn/19.7.1
< Last-modified: Sun, 25 Aug 2019 16:00:30 GMT
< Cache-Control: public, max-age=43200
< Expires: Mon, 14 Oct 2019 07:36:57 GMT
< ETag: "1566748830.0-3052-3932359948"
ほとんどのクライアントは、無効な日付文字列を無視します。これにより、提供されているレスポンスを無視します。これは、誤ったLast-Modified
ヘッダーがLast-Modifiedタイムスタンプなしでキャッシュされるため、条件付きリクエストを実行できなくなるため、キャッシュ可能性に影響を与える可能性があります。
通常、Date
HTTPレスポンスヘッダーは、クライアントにレスポンスを提供するWebサーバーまたはCDNによって生成されます。ヘッダーは通常、サーバーによって自動的に生成されるため、エラーが発生しにくい傾向はあります。これは、無効なDate
ヘッダーの割合が非常に低いことを反映しています。 Last-Modified
ヘッダーは非常に類似しており、無効なヘッダーは0.67%のみでした。しかし、驚いたのは、3.64%のExpires
ヘッダーが無効な日付形式を使用していたことです!
Expires
ヘッダーの無効な使用の例は次のとおりです。
- 有効な日付形式ですが、GMT以外のタイムゾーンを使用しています
- 0や-1などの数値
Cache-Control
ヘッダーで有効な値
無効なExpires
ヘッダーの最大のソースは、人気のあるサードパーティから提供されるアセットからのものです。たとえば、Expires:Tue、27 Apr 1971 19:44:06 EST
など、日付/時刻はESTタイムゾーンを使用します。
ヘッダーを変更
キャッシングで最も重要な手順の1つは、要求されているリソースがキャッシュされているかどうかを判断することです。これは単純に見えるかもしれませんが、多くの場合、URLだけではこれを判断するには不十分です。たとえば同じURLのリクエストは、使用する圧縮(Gzip、Brotliなど)が異なる場合や、モバイルの訪問者に合わせて変更および調整できます。
この問題を解決するために、クライアントはキャッシュされた各リソースに一意の識別子(キャッシュキー)を与えます。デフォルトでは、このキャッシュキーは単にリソースのURLですが、開発者はVaryヘッダーを使用して他の要素(圧縮方法など)を追加できます。
Varyヘッダーは、1つ以上の要求ヘッダー値の値をキャッシュキーに追加するようにクライアントに指示します。この最も一般的な例は、Vary:Accept-Encoding
です。これにより、Accept-Encoding
リクエストヘッダー値(gzip
、br
、deflate
など)のキャッシュエントリが別になります。
別の一般的な値はVary:Accept-Encoding
、User-Agent
です。これは、Accept-Encoding値とUser-Agent
文字列の両方によってキャッシュエントリを変更するようにクライアントに指示します。共有プロキシとCDNを扱う場合、Accept-Encoding
以外の値を使用すると、キャッシュキーが弱められ、キャッシュから提供されるトラフィックの量が減少するため、問題発生の可能性があります。
一般に、そのヘッダーに基づいてクライアントに代替コンテンツを提供する場合のみ、キャッシュを変更する必要があります。
Vary
ヘッダーは、HTTPレスポンスの39%、およびCache-Control
ヘッダーを含むレスポンスの45%で使用されます。
以下のグラフは、上位10個のVary
ヘッダー値の人気を示しています。 Accept-Encoding
はVaryの使用の90%を占め、User-Agent
(11%)、Origin
(9%)、Accept
(3%)が残りの大部分を占めています。
キャッシュ可能なレスポンスにCookieを設定する
レスポンスがキャッシュされると、そのヘッダー全体もキャッシュにスワップされます。これが、DevToolsを介してキャッシュされたレスポンスを検査するときにレスポンスヘッダーを表示できる理由です。
しかし、レスポンスにSet-Cookie
がある場合はどうなりますか? RFC 7234セクション8によると、Set-Cookie
レスポンスヘッダーはキャッシングを禁止しません。これは、キャッシュされたエントリがSet-Cookie
でキャッシュされている場合、それが含まれている可能性があることを意味します。 RFCでは、適切なCache-Control
ヘッダーを構成して、レスポンスのキャッシュ方法を制御することを推奨しています。
Set-Cookie
を使用してレスポンスをキャッシュすることのリスクの1つは、Cookieの値を保存し、後続の要求に提供できることです。 Cookieの目的によっては、心配な結果になる可能性があります。たとえば、ログインCookieまたはセッションCookieが共有キャッシュに存在する場合、そのCookieは別のクライアントによって再利用される可能性があります。これを回避する1つの方法は、Cache-Control``プライベート
ディレクティブを使用することです。これにより、クライアントブラウザーによるレスポンスのキャッシュのみが許可されます。
キャッシュ可能なレスポンスの3%にSet-Cookieヘッダー
が含まれています。これらのレスポンスのうち、プライベート
ディレクティブを使用しているのは18%のみです。残りの82%には、パブリックおよびプライベートキャッシュサーバーでキャッシュできるSet-Cookie
を含む530万のHTTPレスポンスが含まれています。
AppCacheおよびService Worker
アプリケーションキャッシュまたはAppCacheはHTML5の機能であり、開発者はブラウザがキャッシュするリソースを指定し、オフラインユーザーが利用できるようにできます。この機能は廃止されており、Web標準からも削除され、ブラウザーのサポートは減少しています。実際、使われているのが見つかった場合、Firefox v44 +は、開発者に対して代わりにService Workerを使用することを推奨しています。 Chrome 70は、アプリケーションキャッシュをセキュリティで保護されたコンテキストのみに制限します。業界では、このタイプの機能をService Workerに実装する方向へ移行しており、ブラウザサポートは急速に成長しています。
実際、HTTP Archiveトレンドレポートの1つは、以下に示すService Workerの採用を示しています。
採用率はまだウェブサイトの1%を下回っていますが、2017年1月から着実に増加しています。プログレッシブWebアプリの章では、人気サイトでの使用によりこのグラフが示唆するよりも多く使用されているという事実を含め、上記のグラフでは1回のみカウントされます。
次の表では、AppCacheとService Workerの使用状況の概要を確認できます。 32,292のWebサイトでService Workerが実装されていますが、1,867のサイトでは非推奨のAppCache機能が引き続き使用されています。
Service Workerを使用しない | Service Workerを使用する | 合計 | |
---|---|---|---|
AppCacheを使用しない | 5,045,337 | 32,241 | 5,077,578 |
AppCacheを使用する | 1,816 | 51 | 1,867 |
合計 | 5,047,153 | 32,292 | 5,079,445 |
これをHTTPとHTTPSで分類すると、さらに興味深いものになります。 581のAppCache対応サイトはHTTP経由で提供されます。つまり、Chromeがこの機能を無効にしている可能性があります。 HTTPSはService Workerを使用するための要件ですが、それらを使用するサイトの907はHTTP経由で提供されます。
Service Workerを使用しない | Service Workerを使用する | ||
---|---|---|---|
HTTP | AppCacheを使用しない | 1,968,736 | 907 |
AppCacheを使用する | 580 | 1 | |
HTTPS | AppCacheを使用しない | 3,076,601 | 31,334 |
AppCacheを使用する | 1,236 | 50 |
キャッシングの機会を特定する
GoogleのLighthouseツールを使用すると、ユーザーはWebページに対して一連の監査を実行できます。キャッシュポリシー監査では、サイトが追加のキャッシュの恩恵を受けることができるかどうかを評価します。これは、コンテンツの経過時間(Last-Modified
ヘッダー経由)をキャッシュTTLと比較し、リソースがキャッシュから提供される可能性を推定することによりこれを行います。スコアに応じて、結果にキャッシュの推奨事項が表示され、キャッシュできる特定のリソースのリストが表示される場合があります。
Lighthouseは、監査ごとに0%〜100%の範囲のスコアを計算し、それらのスコアは全体のスコアに組み込まれます。キャッシングスコアは、潜在的なバイト節約に基づいています。 Lighthouseの結果を調べると、キャッシュポリシーでどれだけのサイトがうまく機能しているかを把握できます。
100%を獲得したサイトは3.4%のみです。これは、ほとんどのサイトがキャッシュの最適化の恩恵を受けることができることを意味します。サイトの圧倒的多数が40%未満で、38%が10%未満のスコアを記録しています。これに基づいて、Webにはかなりの量のキャッシュの機会があります。
Lighthouseは、より長いキャッシュポリシーを有効にすることで、繰り返しビューで保存できるバイト数も示します。追加のキャッシュの恩恵を受ける可能性のあるサイトのうち、82%がページの重みを最大で1MB削減できます。
結論
キャッシングは非常に強力な機能であり、ブラウザ、プロキシ、その他の仲介者(CDNなど)がWebコンテンツを保存し、エンドユーザーへ提供できるようにします。これにより、往復時間が短縮され、コストのかかるネットワーク要求が最小限に抑えられるため、パフォーマンス上のメリットは非常に大きくなります。
キャッシュも非常に複雑なトピックです。キャッシュエントリを検証するだけでなく、新鮮さを伝えることができるHTTPレスポンスヘッダーは多数あります。Cache-Control
ディレクティブは、非常に多くの柔軟性と制御を提供します。ただし、開発者は、それがもたらす間違いの追加の機会に注意する必要があります。キャッシュ可能なリソースが適切にキャッシュされていることを確認するためにサイトを定期的に監査することをお勧めします。LighthouseやREDbotなどのツールは、分析の簡素化に役立ちます。