午後、思いがけずAlibaba DingTalkのフロントエンドの面接を受けることになり、大変嬉しく思いました。
面接の内容は、これまでのプロジェクトから、Angular
、React
、Express
などの使用技術に及び、自身の理解がまだ不十分であると感じさせられました。
例えば、私がReact
が好きで、大規模プロジェクトではデータ処理のためにRedux
と組み合わせて使う必要があると話すと、Redux
が具体的にどのような問題を解決するのかと問われ、明確に答えることができませんでした。しかし、全体的に見て、面接の前半部分はかなり手応えを感じていました。
しかし、最後に面接官から「HTTP
プロトコルでキャッシュをどのように制御しますか?」という比較的基礎的な質問が出ました。
私は戸惑いました。普段の業務では全く触れる機会がなかったからです。自分の感覚で、ファイル名の変更やHTTP
のheader
に適切なパラメータを設定することで制御するとしか言えませんでしたが、具体的にどのように設定するのか、設定する内容は何なのか、全く答えることができませんでした。きっとここで不採用になるだろうと感じました。しかし、諺にもある通り「人は同じ場所で二度転ぶべからず」です。この機会にHTTP
キャッシュの関連内容を記録しておきたいと思います。
概览
HTTP
でキャッシュを制御する主な方法は以下の通りです。
Expires
Cache-Control
Last-Modified
/If-Modified-Since
Etag
/If-None-Match
それでは、一つずつ見ていきましょう。
Expires
有効期限です。cookies
のExpires
に少し似ています。header
に具体的な有効期限を設定でき、この有効期限内であれば、ブラウザはサーバーにこのファイルをリクエストせず、ローカルキャッシュから直接読み込みます。
上図は私のブログにある
js
ファイルのHTTP header
です。赤枠1のExpires
が現在のDate
から4時間後に設定されているのがわかります。つまり、通常このファイルはExpires
で指定された時間まではローカルキャッシュが直接使用され、サーバーから再取得されることはありません。
注意すべき点として、Expires
はHTTP 1.0
の機能であり、現在ほとんどのブラウザはデフォルトでHTTP 1.1
を使用しているため、Expires
でキャッシュを制御することは推奨される方法ではありません。
Cache-control
Cache-control
はExpires
と基本的に同じ役割で、現在のリソースの有効期間を示し、ブラウザがローカルキャッシュを使用するか、サーバーからリソースを再取得するかを制御します。しかし、異なる点は、Cache-control
の方がより詳細な制御が可能であることです。header
にExpires
が同時に存在する場合、Cache-control
の優先順位が高くなります。
HTTP
ヘッダーCache-Control
の値は、public
、private
、no-cache
、no-store
、no-transform
、must-revalidate
、proxy-revalidate
、max-age
のいずれかです。 各メッセージにおけるディレクティブの意味は以下の通りです。
Public 応答が任意のキャッシュによってキャッシュ可能であることを示します。
Private 個々のユーザーに対する応答メッセージ全体またはその一部が、共有キャッシュによって処理されてはならないことを示します。これにより、サーバーはユーザーの一部応答メッセージのみを記述でき、この応答メッセージは他のユーザーのリクエストには無効です。
no-cache リクエストまたは応答メッセージがキャッシュされないことを示します。
no-store 重要な情報が意図せず公開されるのを防ぐために使用されます。リクエストメッセージで送信されると、リクエストと応答メッセージの両方でキャッシュが使用されなくなります。
**max-age** **クライアントが指定された時間(秒単位)を超えない生存期間の応答を受け取ることができることを示します。**
min-fresh クライアントが現在の時間と指定された時間を加えた時間よりも短い応答時間を持つ応答を受け取ることができることを示します。
max-stale クライアントがタイムアウト期間を超過した応答メッセージを受け取ることができることを示します。max-staleメッセージの値を指定した場合、クライアントはタイムアウト期間の指定された値以内の応答メッセージを受け取ることができます。
図のように、赤枠2の上の
Cache-Control
の欄の値はpublic, max-age=14400
です。これは有効期間が14400s
、つまり4時間であることを意味し、上記のExpires
の有効期限と同じです。しかし、Expires
のようにMon, 07 Mar 2016 17:14:33 GMT
といった具体的な時間を指定する必要はなく、最大寿命の時間を指定するだけで済みます。これは比較的よく使われる方法でしょう。
Last-Modified/If-Modified-Since
**Last-Modified**
はこのリソースの最終更新時間を示します。サーバーはリクエストに応答する際、ブラウザにこのリソースの最終更新時間を伝えます。**If-Modified-Since**
HTTP
リクエストを送信する際、ブラウザはキャッシュされたリソースの最終更新時間をサーバーに送信します。サーバーはこの時間とサーバー上の実際のファイルの最終更新時間を比較します。時間が一致すればHTTP
ステータスコード304
を返し、ブラウザはそれを受け取るとキャッシュされたファイルを直接表示します。時間が一致しない場合はHTTP
ステータスコード200
と新しいファイルの内容を返し、ブラウザはファイルを受け取るとローカルの古いファイルを破棄し、新しいファイルをキャッシュして表示します。Last-Modified
/If-Modified-Since
はCache-control
と組み合わせて使用する必要があることに注意してください。ローカルのリソースが期限切れになった場合(つまり、max-age
で定義された時間を超えた場合)にのみ、If-Modified-Since
を含むリクエストがサーバーに送信されます。
Etag/If-None-Match
**Etag/If-None-Match**
も同様にCache-control
と組み合わせて使用する必要があります。**Etag**
サーバーはブラウザのリクエストに応答する際、ブラウザに現在のリソースのサーバー上での一意な識別子を伝えます。識別子のルールはサーバーによって決定されます。If-None-Match
リソースが期限切れになった場合(つまり、max-age
で定義された時間を超えた場合)、リソースがEtag
を宣言していることがわかると、再度サーバーにリクエストを送信する際にIf-None-Match
(つまりローカルキャッシュされたリソースのEtag
値)を含めます。サーバーはリクエストを受け取った後、If-None-Match
があることを確認し、要求されたリソースのEtag
と照合します。同じであればリソースに変更がないことを示し304
を返し、そうでなければ200
と新しいリソースを返します。
これら4つの方法の優先順位は、以下の図で説明できます。
画像引用元
Etag
の優先順位がLast-Modified
よりも高いことがわかります。
参考文章:
1.ブラウザキャッシュメカニズム
2.ブラウザキャッシュ関連の HTTP ヘッダー紹介
この記事は 2016年3月8日 に公開され、2016年3月8日 に最終更新されました。3499 日が経過しており、内容が古くなっている可能性があります。