仕組みから理解するブラウザキャッシュ

  • 公開日:

Webページの表示速度を改善する手段の一つに、ブラウザキャッシュの利用があります。

単にブラウザキャッシュを利用するだけであればhttpd.confまたは.htaccessに記述を加えるだけでいいのですが、ブラウザキャッシュの仕組みをちゃんと理解した上で使いたかったので色々と調べてみました。

今回の記事では、調べた内容を紹介します。

この記事の目次

Last-ModifiedヘッダーとETagヘッダー

これらのヘッダーでは、ブラウザにキャッシュされたファイルとWebサーバーのファイルとが同じかどうかをブラウザが判断する方法を指定します。ファイルが同一であれば、ブラウザキャッシュが利用され、ファイルの転送量が節約されます。

ブラウザは、前回のアクセスでLast-ModifiedヘッダーまたはETagヘッダーを受け取った場合、条件付きGETリクエストをWebサーバーに送ります。

  • Last-Modifiedヘッダー:If-Modified-Since
  • ETagヘッダー:If-None-Match

ファイルに変更がなければ、サーバーはステータスコード304を送信し、ブラウザキャッシュが利用されます。

Last-Modifiedヘッダー

Last-Modifiedヘッダーを用いたブラウザキャッシュ

Last-Modifiedヘッダーでは、最後に更新された日時をもとにリソースが同じかどうかを判断します。

また、リクエストにIf-None-Matchヘッダーが含まれる場合には、If-Modified-Sinceヘッダーが無視されます。つまり、Last-ModifiedヘッダーとETagヘッダーを併用した場合は、ETagヘッダーが優先されます。

ETagヘッダー

ETagヘッダーを用いたブラウザキャッシュ

Etagヘッダーでは、「エンティティタグ」と呼ばれるリソースを特定するために割り当てられる固有の値(文字列)を用いて、リソースの内容が同じかどうかを判断します。

Apacheの場合、バージョンによって内容は異なりますが、デフォルトでETagが割り当てられます。Apache 2.2では、ETagの値はinode・サイズ・最終修正時刻から作成されます。

FileETag INode MTime Size

Apache 2.4では、サイズ・最終修正時刻から作成されます。

FileETag INode MTime Size

複数台のWebサーバーでサイトを運用している場合は注意が必要です。全く同じ内容のリソースであってもファイルシステムが異なれば、inodeは別の値になります。そのため、複数台のWebサーバーで運用している場合には、Etagの作成にinodeを含めないように設定する必要があります。

ExpiresヘッダーとCatch-Controlヘッダー

リソースの有効期間をブラウザに伝えて、その期間はリソースがキャッシュされるように指定できます。2回目以降の閲覧では、リソースの有効期間を過ぎるかユーザーがキャッシュを消去するまで、ブラウザキャッシュが参照されます。そのため、HTTPリクエストが減り、Webページの表示速度が速くなります。

Expiresヘッダー

Expiresヘッダーでリソースの有効期間を設定することができます。ファイルの種類(MIMEタイプ)ごとに有効期間を変更したい場合には、以下のように記述します。

ExpiresByType image/png "access plus 30 days"

RFCのガイドラインには、有効期間を1年以内に設定するように記されています。

また、HTTPレスポンスにCatch-Controlのmax-ageディレクティブが含まれる場合は、Expiresは無視されます。

Catch-Controlヘッダー

Catch-Controlヘッダーのmax-ageディレクティブを使ってリソースの有効期間を設定することもできます。

<FilesMatch "\.png$">
Header set Catch-Control "max-age=2592000, public"
</FilesMatch>

max-ageの単位は「秒」で記述します。上記の例では、60秒×60分×24時間×30日=2592000秒で、有効期間が30日であることを示しています。

リソースの変更を反映する方法

ExpiresヘッダーまたはCatch-Controlヘッダーによって有効期限が指定されている場合、Webサーバー上でリソースの変更があっても、その変更はブラウザの表示に反映されません。

ユーザーの立場になって考えていますか?

Webサイトの制作や運用に携わっていると、ブラウザキャッシュが原因でリソースを変更してもブラウザの表示に反映されないということはしばしば起こります。そのような場合、強制再読み込み(スーパーリロード)をしてブラウザの表示を確認している人も多いのではないでしょうか。(強制再読み込みの方法については「キャッシュクリアでサイトの修正を反映させる方法」が参考になります。)

ただ、ユーザーの立場から考えると、いつ・どのリソースが変更されたかは分かりません。そのため、Web制作者はユーザーに対して、リソースを変更した際にブラウザがキャッシュではなくWebサーバー上のリソースを参照する「仕組み」を提供する必要があります。その仕組みは、英語で「Cache Busting」と呼ばれています。

クエリ文字列を用いる方法

「クエリ文字列」とは、下記のようにURLの末尾に「?」マークから続く文字列のことです。

<link rel="stylesheet" href="style.css?date=20160925">

本来は、Webアプリケーションに値を渡す方法として用いられるため、例のように「名前=値」の形式で記述されます。ただし、Cache Bustingのためだけに用いるのであれば、「名前=値」の形式である必要はありません。

リソースの名前を変更する方法(URLフィンガープリント)

Googleの「PageSpeed Insights」の解説ページには、次のような記述があります。

たとえば、「my_stylesheet.css」というリソースがあるとします。このファイル名を「my_stylesheet_fingerprint.css」に変更できます。リソースが変更されると、フィンガープリントも変更されるため、URLも変わります。URLが変更されるとすぐに、ブラウザはリソースの再取得を強制されます。

つまり、リソースの名前を変更すれば、ブラウザはWebサーバーからリソースを取得するということです。原理はとても簡単です。

ただし、大規模でリソースの多いサイトを運用していく場合には、

  • リソースを変更した際にどのようなルールでリネームするのか
  • 何らかのプログラムを用いて自動的にリネームするのか手動的にリネームするのか

など、あらかじめ運用の方針を明確に定めておく必要があります。

参考文献

Webサイト

書籍