今回はHTTPレスポンスヘッダの一つ、Expiresヘッダについて紹介します。現在ではCache-Controlヘッダのほうが一般的ですがまだまだ残り続けているヘッダのためしっかり内容を押さえておきましょう。
Expiresヘッダとは
ExpiresヘッダはレスポンスヘッダのひとつでApacheやNginxなどのWEBサーバー側で適切な設定をすることによって、新しいファイルが存在しているかどうかを確認することなく、ブラウザでキャッシュ済みのファイルを強制的に適用するEtagやIMSより優先度が高いヘッダです。
キャッシュ済みのファイルを強制的に読み込む期間を指定するため、Expiresヘッダで指定した期間は強制的にコンピュータ内に保存されたキャッシュファイルを読み込むことになります。
Expiresヘッダサンプル
Expiresヘッダはhttp1.0のバージョンから存在し、netscapeの仕様となります。一部のブラウザではサポートされていないケースがあるためMax-ageヘッダと一緒に出力してあげることが一般的。
Apacheの設定例
さて、Apacheの場合以下のように設定すればExpiresヘッダが出力されるようになります。
ExpiresActive On ExpiresByType image/png "access plus 2 months" ExpiresByType image/jpg "access plus 2 months" ExpiresByType image/gif "access plus 2 months"
このように、拡張子毎に日付を設定することが可能です。あまり頻繁に変更されないファイルを対象とするのがいいでしょう。
ちなみにRFC 2616 “Hypertext Transfer Protocol — HTTP/1.1″ では以下のように定義されてる。
The Expires entity-header field gives the date/time after which the response is considered stale.
http://tools.ietf.org/html/rfc2616#section-14.21
expiration time は HTTP-Date 形式(rfc1123-date | rfc850-date | asctime-date)でかく。 Expires: Thu, 02 Dec 1995 12:00:00 GMT
Expiresヘッダの使いどころ
Expiresヘッダは指定された期日が過ぎるまで新しいコンテンツを取りに行かないという仕様のため、頻繁に更新されるようなコンテンツには適していません。しかし、逆にIf modified Sinceも送られないため、304レスポンス負荷が発生することもありません。そこで、EtagとLast-Modifiedが既に付与されている場合のExpiresヘッダの期日は状況によって以下の通り調整すべきです。
極力ブラウザにキャッシュさせ、コンテンツ更新判定をさせたい
Expiresヘッダが付与されている場合、EtagとIf-Modified-Sinceを上書きしてしまいます。つまり、最新のコンテンツをサーバーから取りに行くことをせずExpiresヘッダに付与されている期間までブラウザのキャッシュを読みにいってしまいます。
極力ブラウザにキャッシュさせつつも、更新判定を行いたい場合は、Expiresヘッダに過去の日付を指定すれば問題ありません。
サーバー側のレスポンスヘッダ
Expires "Mon, 26 Jul 1997 05:00:00 GMT"
ブラウザ毎に片方しかサポートしていない場合があるので、Cache-Control "max-age=0"というヘッダも合わせて付けておいた方が良いでしょう。
この場合、ブラウザ側ではExpiresヘッダをみて既に期限が切れていることを確認し、つぎに条件つきリクエスト(If-Modified-Since、If-None-Match)をサーバへ送ります。
サーバー側は、送られてきたIf-Modified-Since、If-None-Match でコンテンツの変更ありなしを判断して 304レスポンスを返します。サーバーから304レスポンスを受け取った場合、ブラウザはローカルのキャッシュを利用するという動作になります。
Expires: -1について
過去の日付を指定すれば期限切れと判断されます。しかし、毎回過去の日付をしらべてられないですよね。そこで、共通のある値を指定することでどのようなコンテンツであれ、期限切れと定義させる方法があります。
RFCでは以下のように定義されています。
HTTP/1.1 clients and caches MUST treat other invalid date formats, especially including the value “0”, as in the past (i.e., “already expired”).
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
このように-1というHTTP-DATE以外の値を指定してあげて不正な日時と判断させ、結果期限切れとしてしまう荒技もあります。
強制的にキャッシュさせたい場合
先ほどの例は少し矛盾しています、なぜならそもそも304レスポンスを返してほしければ、Expiresヘッダを付与すべきではないからです。Expiresヘッダを付与する場合はむしろ、「強制的にキャッシュさせたい」といった場合に利用されることのほうが多いでしょう。
ブラウザにキャッシュさせる命令をExpiresヘッダで行うのは簡単です。
サーバー側のレスポンスヘッダ
Expires "Mon, 26 Jul 2016 05:00:00 GMT"
かなり未来の日付を設定していますが、このようにすれば指定期日までサーバー自身にリクエストを送信しないため、サーバー側の負荷が大幅に下がります。
気をつけなければいけない点は、1年以上先の日付は推奨されていないことです。10年とか100年先とかはやめましょう。
ファイルの最終更新日以降指定期間だけ有効
つぎは、ファイルの最終更新日が過ぎてから特定の期間だけサーバーにアクセスさせないようなトリッキーな設定も可能です。
Apacheの場合以下のように設定します。
ExpiresDefault "modification plus 5 minutes"
このようにするとファイルの最終更新日から5分間はサーバーに問い合わせないという動作が可能です。
キャッシュさせたくない場合
そもそも、ブラウザにキャッシュさせたくない場合は、Expiresヘッダは付与すべきではありません。またETAGやLast-Modifiedも削除すべきです。しかし、手軽に実現出来る一番簡単な方法は以下のキャッシュコントロールヘッダを付与することです。
Cache-Control "no-cache"
no-cacheを付与することによって、毎回最新のコンテンツを取りに行くことになります。こちらはアクセス毎に内容が変更されたりサーバーにアクセスしてもらわないと困るようなコンコンテンツの場合、特にスクリプト言語等で生成する動的コンテンツなどに適しています。
Expiresヘッダの注意点
最後にExpiresヘッダの注意点をいくつかまとめます。
Expiresの日付は1週間以上に設定すること。
RFCのガイドラインに違反するので、1年以上先には設定しないこと。
EtagやLast-Modifiedより強いキャッシュなので更新の多いページや動的更新されるページでは利用しない。
サーバーに問い合わせないためアクセスログも収集出来なくなる。
特に最後のアクセスログが収集出来ないというのは状況によって致命的になります。しっかり検討してExpiresヘッダを付与しましょう。
HTTP/1.1 ではキャッシュをより細かく制御するために Cache-Control ヘッダーが追加されより柔軟なキャッシュコントロールが可能となりました。次回はそのあたりを詳しく説明していきます。