Spring BootのETagとCache-Controlを完全解説!初心者でもわかるブラウザキャッシュ設計
生徒
「ページの読み込みを速くしたいんですが、ブラウザキャッシュってどうやって使えばいいんですか?」
先生
「それならETagやCache-Controlヘッダーを使うといいですよ。Spring Bootではこれらを簡単に使える仕組みがあります。」
生徒
「キャッシュってなんとなくは分かるんですが、実際にどう設定するかまでは分からなくて…」
先生
「では、ETagやCache-Controlの基本から、Spring Bootでの実装まで、わかりやすく解説していきましょう!」
1. ブラウザキャッシュの基本とは?
Webアプリケーションのパフォーマンスを向上させるために欠かせないのがブラウザキャッシュです。キャッシュを活用すれば、画像やJSONなどのレスポンスデータを一度取得すれば、次回以降はダウンロードせずに表示できるようになります。
代表的な仕組みには以下の2つがあります。
- ETag:レスポンスのハッシュ値などを返して、変更がなければ304(Not Modified)を返す仕組み
- Cache-Control:クライアント側で一定期間キャッシュを保存できるようにするヘッダー
2. Spring BootでETagを有効にするには?
Spring Bootでは、WebMvcConfigurerの設定でETagを簡単に有効化できます。下記のように設定ファイルに記述するだけです。
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
}
@Bean
public FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagFilter() {
FilterRegistrationBean<ShallowEtagHeaderFilter> filter = new FilterRegistrationBean<>(new ShallowEtagHeaderFilter());
filter.addUrlPatterns("/*");
return filter;
}
}
このShallowEtagHeaderFilterは、レスポンス内容のハッシュを自動で生成し、If-None-Matchリクエストヘッダーに基づいて304を返してくれます。
3. Cache-Controlでキャッシュ期間を明示的に設定
Cache-Controlヘッダーを使うことで、ブラウザに対してキャッシュの保存期間や動作を指示できます。Spring Bootでは以下のようにControllerで個別に設定できます。
@GetMapping("/static-content")
public ResponseEntity<String> getContent() {
return ResponseEntity.ok()
.cacheControl(CacheControl.maxAge(30, TimeUnit.DAYS))
.body("キャッシュ可能なコンテンツ");
}
maxAgeの設定により、ブラウザはその間リクエストせず、キャッシュを使用します。CDNと組み合わせるとさらに効果的です。
4. 静的リソース(JS・CSS・画像)へのキャッシュ設定
Spring Bootではapplication.propertiesで静的リソースのキャッシュ制御が可能です。
spring.web.resources.cache.cachecontrol.max-age=60d
spring.web.resources.cache.cachecontrol.cache-public=true
この設定により、/staticや/publicフォルダ内の画像やJavaScriptに対して、自動的にキャッシュヘッダーが付与されます。
5. ETagとCache-Controlを組み合わせて最適化
ETagとCache-Controlは、併用することで非常に高いパフォーマンスを発揮します。
- まずは
Cache-Controlで期限内のアクセスをキャッシュで処理 - 期限が切れた場合、
ETagによる304判定で再ダウンロードを回避
このように組み合わせることで、ユーザーにとっても快適で、サーバー負荷も軽減される仕組みを構築できます。
6. APIレスポンスにETagを独自に設定する方法
自動生成されたETagだけでなく、独自ロジックで生成したETagを手動で設定することも可能です。例えば、データベースの更新日時やハッシュを使って次のように実装できます。
@GetMapping("/api/data")
public ResponseEntity<String> getData(@RequestHeader(value = "If-None-Match", required = false) String ifNoneMatch) {
String currentEtag = "\"123456789\"";
if (currentEtag.equals(ifNoneMatch)) {
return ResponseEntity.status(HttpStatus.NOT_MODIFIED).eTag(currentEtag).build();
}
return ResponseEntity.ok().eTag(currentEtag).body("データの内容");
}
If-None-Matchヘッダーが送信されたときに、それと一致すれば304を返すことで、効率的な通信が可能になります。
7. キャッシュ設計時の注意点
キャッシュは便利ですが、設計を間違えると古いデータが表示されたままになるなどの不具合が発生します。以下のポイントを意識しましょう。
- 更新頻度が高いAPIにはキャッシュを使わない
- ユーザー別のレスポンスにはキャッシュさせない
- URLやパラメータでバージョン管理をする(例:
?v=1.2)