はじめに
Spring Boot 3.2以降(内部的にはSpring Framework 6.1以降)では、存在しない静的リソースに対するリクエストが処理される際の挙動が変更され、従来の単純な404エラー返却ではなく、NoResourceFoundException
がスローされるようになりました。
本記事では、この仕様変更の背景と影響、そして404エラーを正しく返すために採用したNoResourceFoundException専用のグローバル例外ハンドラーによる対策について解説します。
仕様変更の概要
従来、Spring MVCでは存在しないURLへのリクエストに対して、HTTP 404エラーを直接返す処理が行われていました。しかし、Spring Framework 6.1以降、静的リソースの解決時にリソースが見つからなければ、内部でNoResourceFoundException
がスローされるようになりました。
この変更はエラー処理の一貫性と柔軟性を向上させるために導入されましたが、既存のグローバル例外ハンドラーがすべての例外(Exception)を一括処理している場合、意図せず500エラーとして扱われるという問題が発生します。
問題の背景
-
NoResourceFoundExceptionの仕様変更
Spring Boot 3.2(Spring Framework 6.1)からは、静的リソースが存在しない場合にResourceHttpRequestHandler
がNoResourceFoundException
をスローします。 -
既存のグローバル例外ハンドラーの影響
アプリケーション内で@ControllerAdvice
を用いたグローバル例外ハンドラーが@ExceptionHandler(Exception.class)
などで全例外を一括処理していると、NoResourceFoundException
もこのハンドラーでキャッチされ、結果としてHTTP 500エラーとなってしまいます。
対策:NoResourceFoundException専用のグローバル例外ハンドラーの実装
最も確実な対策は、NoResourceFoundException
専用のハンドリングを行うことです。以下のような@ControllerAdvice
クラスを実装することで、存在しない静的リソースへのアクセス時に正しくHTTP 404を返すことが可能になります。
import org.springframework.boot.web.servlet.error.NoResourceFoundException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NoResourceFoundException.class)
public ResponseEntity<Object> handleNoResourceFound(NoResourceFoundException ex) {
// 必要に応じてログ出力やエラーメッセージの加工を行う
String errorBody = "指定されたリソースが見つかりませんでした。";
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorBody);
}
}
このハンドラーを導入することで、静的リソースが存在しない場合にNoResourceFoundException
がスローされても、グローバルハンドラーがキャッチし、HTTP 404として適切なレスポンスを返すようになります。
まとめ
Spring Boot 3.2以降では、静的リソースが見つからない場合にNoResourceFoundException
がスローされる仕様変更が導入され、既存のグローバル例外ハンドラーで全例外を一括処理していると、本来404とすべきリクエストが500エラーとして扱われるケースが発生します。
私の場合、デフォルトハンドリング(方法2)やResourceHandlerの優先順位調整(方法3)はうまくいかなかったため、NoResourceFoundException専用のグローバル例外ハンドラーを実装する方法で問題を解決しました。
この方法により、存在しないリソースへのリクエストで正しく404エラーが返されるようになり、ユーザやクローラに対して意図した動作を提供できるようになりました。