🤔

ブラウザキャッシュ対策(キャッシュバスティング)

2024/04/22に公開

はじめに

こんにちは!
オアシステクノロジーズの山本です。

ブラウザキャッシュのせいで、静的コンテンツが更新されないという例は多くの方が経験されたことある問題かと思います。

SpringBoot+Thmeleaf の場合、この問題に対して

  • 静的ファイル名自体にハッシュ値を付与する
  • バージョン毎にURLを変更する

といったキャッシュバスティング機能が提供されています。

↓詳細は以下のリンクを参照ください。
Spring ドキュメント

この方法がそのまま適用できればよいのですが、のっぴきならない事情で、他の方法が必要な場合もあります。

その他の方法として、参照するリソース(CSS/JavaScriptなどの静的ファイル)のURLにキャッシュバスターと呼ばれるパラメータを付与するという方法を検討したいと思います。

今回とる方法

  • アプリケーションの起動毎にランダムなハッシュ値とする
  • 生成したハッシュ値をリソースのURLに付与

リソースのURLに付与したハッシュ値がアプリケーション起動毎に変更されることで、ブラウザキャッシュを無効化する

※[VersionResourceResolver](https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/resource/VersionResourceResolver.html)とか使えばもっとかっこよくできるかもしれない。

こんな感じ

application.propertiesの設定(起動毎にランダムな値を取得)


static.resource.version=${random.value}

Interceptorの実装(postHandle:ビューがレンダリングされる前に呼び出されるメソッド)

import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.util.DigestUtils;

@Component
public class StaticResourceInterceptor implements HandlerInterceptor {

    @Value("${static.resource.version}")
    private String staticResourceVersion;

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        if (modelAndView != null) {
            String hash = DigestUtils.md5DigestAsHex(staticResourceVersion.getBytes()); // ハッシュ値をMD5で計算
            modelAndView.addObject("staticResourceVersion", hash); // モデルにハッシュ値を追加
        }
    }
}

Thmeleafの実装

 <link th:href="@{/static/styles.css(v=${staticResourceVersion})}" rel="stylesheet" type="text/css">

難点

結局Thmeleaf側でバージョン指定の実装が必要になるので、うっかり忘れてしまうということが起こりえる。。。
アプリケーションの再起動が必要。。。静的ファイルの差し替えだけで対応できない。。。
変更していない静的ファイルのキャッシュも無効化されてしまう。。。
アプリケーションの起動毎にハッシュ値が変わるので、複数サーバーでの同期がとれない。。。

@{/static/styles.css} だけで行きたいという方は

以下のサイトが参考になるかもしれません。
https://www.bunkei-programmer.net/entry/2016/10/22/163544

まとめ

多くの方が経験されことのある、ブラウザキャッシュの問題に対して、キャッシュバスティングを実装する方法を検討しました。どなたかの参考になれば幸いです。

Discussion