よくある事例だと思います。
画像を更新するためにアップロードしたら、その画像がすぐに反映されず、古い方の画像が残っている場合ですね。
これまで自身ではすぐに「キャッシュされてるな」と気づくので、F5キー押すなりすればいいだけとさして気にせず過ごしてきました。
記事にすることにしたきっかけ
最近ユーザーから、まさにこのケースに当てはまる問い合わせがありました。 「ハンコの画像をアップロードしても、古い方のハンコの画像が出てきます。直してください。」と。 当然のように、
それはキャッシュに残った画像が使われている状態だと思います。
F5キーを押すなどすれば、新しい画像が表示されるのでお試しください。
とお答えしました。これにて一件落着。。。。。ではなかった!
気付き
「エンジニアの方には常識なのかもしれないが、我々には今後も「バグ」に見えることが多いだろう。毎回問い合わせることになってしまうので、なんとかならないか?そちらも手間が減って楽では?」
なるほど・・・「たった1つ2つキーを押すだけ」と思っていた常識は、必ずしも常識ではないことに気付かせていただきました。
というわけで本題です
キャッシュ画像が使われてしまうことを回避する方法は、すぐにいくつか見つかりましたが、どれもイマイチでした。
たとえば.htaccess
にキャッシュを禁止するように書く → 開発環境はapache
だからいいけど本番はnginex
だった・・・とか。 まぁなんとかなるけど、WEBサーバーごとに設定するのも、他のキャッシュも止めてしまうのも何だし、とか。
採用した方法
htmlの<img>タグにパラメーターを付加することにしました。ただ、使い方に誤解があったので、その部分を共有しようと思います。
具体的な書き方:
<img src="hogehoge.jpg?[t=hhMMss]" alt="hankoimage">
[hhMMss]は、今回は「現在時刻」を入れる、という意図で、実はどんなものでも構いません。ただし、表示される都度、別の文字列が入るようにします。たとえば現在時刻が12:34:56だった場合、
<img src="hogehoge.jpg?t=123456" alt="hankoimage">
となるわけです。
Laravelを採用しているため、最終的にはこんな記述になりました。
<img src="{!! route('hogehoge.fugafuga_info.hanko_image', ['t'=>time()]) !!}" alt="hankoimage">
違和感
さきほど「使い方に誤解」と書きました。この実装をメンバーに依頼したところ、
アップロードする画像のファイル名にも[hhMMss]を追加して、”hogehoge123456.jpg”となるようしてくれていました。
「t=hhMMss を加えるのでファイル名もそろってないといけない」という考えでした。
実はひるやもり
本人もきちんと理解できていなかったので、「これはなんか違和感がある。理解しよう。」ということになりました。
解説
結論からすると、まず、アップロードする画像ファイル名は、加工する必要はありません。上記の例では`”hogehoge.jpg”`のままで大丈夫です。
そして、['t'=>time()]
の部分の見方ですが、
`”hogehoge.jpg”`というファイルをサーバーに要求する際に、ダミーの追加パラメーター ['t'=>time()])
を付与していて、しかもそのパラメーターは毎回変化するので、ブラウザが「別の画像が来るはずだ」という解釈をするため、キャッシュ画像が「使えない」と判断する。なので、キャッシュ機能を迂回させる(だます)ことができる。
ということのようです。
サーバーサイドには、プログラムに何も改変しません。追加パラメーター['t'=>time()]
が付いてきますが、無視して処理していいので、何も変更しなくて良いのでした。
ただただ <img> タグの src=
に、ダミーの乱数的なパラメーターを付与するだけで、キャッシュ機能が迂回できるのでした。
以上です。