はじめに
業務で、画像(img)がキャッシュから取得することで想定外の挙動をする事態になっており対応した時に
「そもそも『キャッシュ』についてよく理解していないな…」
と痛感したので、対応にすごく時間がかかったので自分用メモ
※「キャッシュ」と一言で言ってもいろんなキャッシュがあるので、前提として「ブラウザキャッシュ」のみを取り上げる
※以下「キャッシュ」=「ブラウザキャッシュ」とする
キャッシュについて
キャッシュとは?
https://www.siteengine.co.jp/blog/web-cash/
- 一度サーバーから取得したデータを一時保管する機能
- クライアントとサーバーの間に存在する
- クライアントから全く同じデータを取得するリクエストを受けたら自動でキャッシュからデータを取得する
メリット
https://www.siteengine.co.jp/blog/web-cash/
サーバーへの負荷軽減
サーバーへのリクエストを必要な分だけ送信出来る
サイトの読み込み時間短縮
サーバーからのレスポンス待たなくていい
どこに保存される?
ブラウザ
- 保存先はブラウザによってまちまち
- Chromeの場合は以下
%LOCALAPPDATA%\Google\Chrome\User Data\Default または %LOCALAPPDATA%\Google\Chrome\User Data\Profile
※他のキャッシュだとRedisなどのデータベースをキャッシュとして使うことも多々ある
キャッシュの内容確認は難しい
- 内容確認は上記パスを見に行くことだが、ファイル名が「data...」「f...」などわけのわからないファイル名になっているので、実質不可
- imgのsrcやcssのパスで保存されているわけではない
- 「どうしても確認したい」という場合は以下記事参照
https://aprico-media.com/posts/1338#:~:text=Chromeのキャッシュは、Windows,に保存されています。
キャッシュの削除方法
- 上記パスの削除したいファイルの削除
- 現在のブラウザのキャッシュだけ削除ならスーパーリロード
保存されるキャッシュの単位
その他
bfcache
- ブラウザの戻る、進むボタンを押したときに使用する通常のブラウザキャッシュとは別でデータを保存、取得されるキャッシュ
キャッシュの無効化
https://zenn.dev/mindwood/articles/ba4594c53a93b0
コチラの4種類のやり方
1, METAタグ指定
// 追加 <meta http-equiv="Cache-Control" content="no-cache">
2, Cache Busting
<link href="https://example.com/css/style.css?ver=210615" rel="stylesheet">
?ver=***
とバージョンを付けたりするとリクエストの度に参照するパスが変わるので、必ずサーバーへアクセスするようになる- 更新頻度が高い(imgのsrc属性など)であればtimestampsのパラメータに現在時刻(UNIX時間)を持たせるのも選択肢の一つ
3, HTTPレスポンスヘッダーで制御
<Files ~ ".(jpe?g|png|gif)$"> Header set Cache-Control "no-cache" </Files>
<?php header('Cache-Control: no-cache');
4, JavaScriptでキャッシュを無視
$('.container img').each(function(index, element) { const src = $(element).attr('src'); $(element).attr('src', src + '?' + new Date().getTime()); });
- JSで手動でimgのsrcにパラメータとその値を持たせることで、Cache Bustingを実現
Laravelでのキャッシュの無効化↓
1, Controllerからview単位でキャッシュ無効化
https://qiita.com/MR_ROBOT/items/46aeacd6590e3e500c46
return response(view('example')) ->withHeaders([ 'Cache-Control' => 'no-store', ]);
2, ミドルウェアでキャッシュ無効化
https://traveler0401.com/laravel-security/
<?php namespace App\Http\Middleware; use Closure; class ResponseHeader { public function handle($request, Closure $next) { $response = $next($request); // デフォルトは「no-cache, private」だが、明示的に記載 $response->header('Cache-Control', 'no-cache, private'); return $response; } }
ただ、2, のやり方ではLaravelの仕様上、キャッシュしきれないデータがあるので注意
https://zenn.dev/yuzuyuzu0830/articles/011681894a0f6b
やるなら、no-store
にする必要がある
// デフォルトは「no-cache, private」だが、明示的に記載
$response->header('Cache-Control', 'no-store, private');
キャッシュからデータを取得したか否かの判定方法
- JavaScriptの
pageshow
イベントにあるpersisted
プロパティで判定可能
pageshow : https://developer.mozilla.org/ja/docs/Web/API/Window/pageshow_event
persisted : https://developer.mozilla.org/en-US/docs/Web/API/PageTransitionEvent/persisted
- ドキュメントそのままですがこれで、ページ遷移時にキャッシュから取得したデータであればconsoleが表示
window.addEventListener('pageshow', function(event) { if (event.persisted) { console.log('Page was loaded from cache.'); } });
- ただ、これだと「HTMLファイルだけの判定しかできないのでは…」と使いどころがイマイチ思い当たらない。
おわりに
- メモ書きなので、間違ったところがあるかもです。
- 間違った理解していれば、ご指摘いただけますと幸いです。
- 最後になり申し訳ないですが、参考にさせて頂いた記事については感謝申し上げます。