.htaccessからブラウザキャッシュを設定

/ Web

.htaccessからブラウザキャッシュを好きな期限で設定する方法をメモしておく。

AddTypeでMIMEタイプを追加しておく

AddType font/woff2 .woff2
AddType font/woff .woff
AddType font/otf .otf
AddType font/ttf .ttf
AddType image/webp .webp
AddType audio/webm .weba
AddType video/webm .webm

のように今の環境で認識されていないMIMEタイプを明示的に追加しておく。これらを指定しておかないと後のType指定でapplication/octet-streamとして配信されてしまう。

ブラウザキャッシュを設定するしないかからわずapplication/octet-streamでの配信はそれがフォントなのか画像なのか素性がわからないため警戒の対象となるらしい。ので設定したほうがよい。

Expiresヘッダを設定する

https://httpd.apache.org/docs/2.2/ja/mod/mod_expires.html

mod_expiresが動いていると次の行を追加することでそのMIMEタイプの静的ファイルを転送するときにExpiresヘッダを付加してくれるようだ。

<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/css "access plus 30 days"
ExpiresByType text/javascript "access plus 30 days"
ExpiresByType image/jpeg "access plus 30 days"
ExpiresByType image/gif "access plus 30 days"
ExpiresByType image/png "access plus 30 days"
ExpiresByType image/svg+xml "access plus 30 days"
ExpiresByType image/webp "access plus 30 days"
ExpiresByType image/bmp "access plus 30 days"
ExpiresByType video/3gpp "access plus 30 days"
ExpiresByType video/3gpp2 "access plus 30 days"
ExpiresByType video/mp2t "access plus 30 days"
ExpiresByType video/mpeg "access plus 30 days"
ExpiresByType video/webm "access plus 30 days"
ExpiresByType video/x-msvideo "access plus 30 days"
ExpiresByType audio/midi "access plus 30 days"
ExpiresByType audio/x-midi "access plus 30 days"
ExpiresByType audio/mpeg "access plus 30 days"
ExpiresByType font/woff A12960000
ExpiresByType font/woff2 A12960000
ExpiresByType font/ttf A12960000
ExpiresByType font/otf A12960000
ExpiresByType font/vnd.ms-fontobject A12960000
</IfModule>

構文は見ての通りExpiresByTypeから始まって次にMIMEタイプ、そのあとの指定は人間にわかりやすくaccess plus 30 days などとするかA12960000と秒数で指定するかどちらでもよい。そのほか、

  • ExpiresDefaultでデフォルトで付与する秒数を指定

  • A=accessとM=modificationでそれぞれクライアントのアクセスを起点、ファイルのタイムスタンプを起点で期限を設定できる。

  • 秒数もしくはplus XX

    • years
    • months
    • weeks
    • days
    • hours
    • minutes
    • seconds

    を指定する。

weeksまでならともかくmonthsは具体的な秒数がはっきりしない所がある。もちろんこの場合のmonthsは月に関わらず30daysとするみたいな決まりがあるのかもしれないがそこに決まりが必要な時点で無駄。単なる設定ファイルで人にわかりやすい必要はそんなに無いので秒数を指定すればよい。

Cache-Ccontrolヘッダを設定

https://httpd.apache.org/docs/2.4/ja/mod/mod_headers.html

mod_headersからCache-Controlヘッダを設定する。

<IfModule mod_headers.c>
<filesMatch "\.(css|js|jpeg|jpg|gif|png|svg|svgz|wbmp|webp|ico|jng|bmp|3gpp|3gp|ts|mp4|mpeg|mpg|mov|webm|flv|m4v|mng|asx|asf|wmv|avi|mid|midi|kar|mp3|ogg|m4a|ra)$">
Header set Cache-Control: "max-age=2592000"
</filesMatch>
<filesMatch "\.(woff|woff2|ttf|otf|eot)$">
Header set Cache-Control: "max-age=12960000"
</filesMatch>
</IfModule>

拡張子でマッチングしてそのファイルを転送する際に指定したヘッダを付与する。

とにかく静的ファイルにヘッダを付与するとこういう内容になる。Cache-Control: "max-age=xxxx, public"とある場合があるが、publicはデフォルトなので省略してよい。max-ageには秒数を指定する。Expiresの指定と被っているので指定は必要ないとも考えられるがブラウザからレスポンスヘッダをいろいろ見た結果わりと重複して付与している例はある。

秒数に関してはExpiresの指定と同一にしておくのが良いだろう。その際さきほどmonthsで指定していると正確な秒数がわからないので面倒になる。

動作確認

以上を設定したら動作を確認するのだが、これはブラウザの検証ツールからレスポンスヘッダを直接確認するのが簡単。Firefoxであれば右クリックの「要素を調査」から「ネットワーク」を選んでF5で再読み込みなどすれば次の画面でレスポンスヘッダを確認できる。実際にキャッシュが効いているか確認するのは更新などしないといけないので面倒。

レスポンスヘッダをFirefoxの要素を調査から確認

実際の動作が効いていない場合はSet-Cookieが設定されていないか確認する。これがヘッダに付与されているとキャッシュが効かない。

Apacheのモジュールが動いていない場合

これでヘッダにExpiresなどが付与されていない場合はモジュールが有効になっていないなどがあり得る。例えばmacOSの場合なら/etc/apache2/httpd.confを開いて以下のような当該行のコメントアウトを解除する。

...
#LoadModule logio_module libexec/apache2/mod_logio.so
LoadModule env_module libexec/apache2/mod_env.so
#LoadModule mime_magic_module libexec/apache2/mod_mime_magic.so
LoadModule expires_module libexec/apache2/mod_expires.so  <!----
LoadModule headers_module libexec/apache2/mod_headers.so  <!----
#LoadModule usertrack_module libexec/apache2/mod_usertrack.so
##LoadModule unique_id_module libexec/apache2/mod_unique_id.so
LoadModule setenvif_module libexec/apache2/mod_setenvif.so
LoadModule version_module libexec/apache2/mod_version.so
#LoadModule remoteip_module libexec/apache2/mod_remoteip.so
#LoadModule proxy_module libexec/apache2/mod_proxy.so
...

そのあと

sudo apachectl restart

とすればモジュールがロードされる。httpd.confの場所や再起動のやり方は他のLinuxなど環境によって異なる。