初めに
そもそも、なぜこのような記事を書くことになったかというとバイト先で「HTTPについて調べます。」と先輩に宣言して、どうやって成果物を出すか迷っていた際に、「記事にすれば、良いんじゃないか?」と思ったからです。
その中でも今回はCacheに関するHTTPヘッダーについてまとめました。その理由はいくつかありますが、
- キャッシュという仕組みをあまり知らなかったから
- Webのパフォーマンスを上げる業務ができるとカッコ良さそうだったから
などが挙げられます。
そして、誤りがある場合は指摘をいただきたいです。もう一度調べ直した上で、修正/加筆を行います。理由は以下の通りです。
この記事を見たHTTPについて知らない人に誤った情報が渡ってしまうことを防ぐため。
私自身の勉強のため。
対象読者は以下です。
- Cacheについて知っている。
- HTTPの構成は何となく分かっている。
- Webアプリケーションを作ったことがある。
- Cache-Control?何それ美味しいの?状態、要するに何も知らない。
HTTPの構成が分からない人はよければ以前書いた記事を読んでください
HTTPリクエスト/レスポンスの構成要素を初心者にも分かるように解説してみた
Cache-Controlヘッダー
Cache-Controlとはその名の通りキャッシュを制御することを目的としたヘッダーです。では、Cache-Controlが取れる値についていくつか説明します。
-
no-cache
キャッシュするかどうかをオリジンサーバーに問い合わせてから、キャッシュデータを返すかどうかを決めます。キャッシュするかどうかはETag/If-Modified-Sinceヘッダーの値とオリジンサーバーがそれぞれに対応する値を比較することで決めています。
問答無用でキャッシュしない訳ではありません。これに関しては誤った記載があった記事がQiitaで多くのいいねがされていますが、それは過ちだと思われるので、注意してください。 -
max-age
max-age=nでキャッシュの有効期間を指定できます。例えば、max-age=3600と指定すると3600秒(一時間)の間に同一のリソースにリクエストする際には、キャッシュを使用します。以前にそのリソースにリクエストして、その時に発生するレスポンスから3600秒を数え始めます。
この詳細はこのページが一番分かりやすかったです。 -
no-store
リクエスト/レスポンス時にキャッシュを一切使用しない。
Last-ModifiedとIf-Modified-Since
Last-Modifiedヘッダーはレスポンスヘッダーの一種です。オリジンサーバーがリソースに対して最後に変更があったと考える日付と時刻を値として持ちます。
If-Modified-Sinceヘッダーはリクエストヘッダーの一種です。Last-Modifiedに設定された値を持ちます。この値とオリジンサーバーが持つリソースの変更日時を比較することでキャッシュするかどうかを決定します。リクエスト時に送信したIf-Modified-Sinceヘッダーの値以降にリソースが変更されているとオリジンサーバーが認識している際に、200(OK)を返します。変更されていなければ、304(Not Modified)が返されます。
EtagヘッダーとIf-None-Match
ETagヘッダーにはファイルに紐付けられたハッシュ値を持ちます(下記のコード参照)。これがレスポンスとしてサーバーから返されます。この値はサーバーによって決め方が異なります。ファイルサイズ/更新日時/コンテンツの内容等を単体または複数の組み合わでハッシュ化していることが多いようです。
ETag: "3ca531-1f467-5683773bfe880;56888f86e23bd"
レスポンスで返ってきたEtagの値をIf-None-Matchヘッダーの値として持たせて、リクエストを送信します。
If-None-Match: "3ca531-1f467-5683773bfe880;56888f86e23bd"
サーバーが保持するリクエストされたファイルに紐付けられているハッシュ値とIf-None-Matchの値が同じであれば、キャッシュします。異なる場合はサーバーからデータを返します。
Expiresヘッダー
下記のように日時が値として設定されます。
Expires: Wed, 04 Apr 2018 08:26:45 GMT
RFC7234に2018/03/29 16:02(何秒かは忘れた)にアクセスした際にはこのようなExpiresが返ってきました。この場合は2018/04/05 07:17:38秒までに同一のリソースにリクエストした際には強制的にキャッシュされます。実際にアクセスすると304が返ってきます。ちなみに、RFCではExpiresの期限は最大でも一年の寿命にするように指定されています。
個人的な疑問~ETagとIf-Modified-Sinceって同じことしている様に見えるのになぜ共存しているのか~
これがよく分かっていません。キャッシュという仕組みを実行するだけなら、If-Modified-Sinceを使用すれば、実現できる気がしています。どなたか分かる方にコメントを頂けると幸いです。
いくつか調べてみると、具体例が出てきた。
「同一のURLで日本語版サイトと英語版サイトが用意されている場合に、それぞれは別々のリソースであり、同一のリソースとしてキャッシュしてはいけない。そのためには日本語サイトに紐づくETagの値、英語サイトに紐づくETagの値を用意することで、日本語サイトでキャッシュするのか、英語版サイトでキャッシュするのかを決める。」
というものだったが、いまいち分からなかった。
最後に
キャッシュは文面上の理解に留まっており、正直、伝えきれていない箇所が多いように思えました。これからは実際にサーバー(Nginx,Apache等)の設定を調べたり、クラウドサービス(AWS)のインプットとアウトプットをすることでキャッシュの理解を少しづつ深めたいと思っています。そして、その時にまたこの記事をリライトしたいです。ただ、この記事でも誤っている箇所はないと思っているので、参考になれば幸いです。
もちろん、誤っている箇所があった場合はすぐにコメントを頂きたいです。宜しくお願い致します。
参考文献
- Real World HTTP 歴史とコードに学ぶインターネットとウェブ技術
- Webを支える技術
- HTTPの教科書
- MDN
- RFC