最新の安定バージョンについては、Spring Framework 6.2.3 を使用してください!

エラーレスポンス

REST サービスの一般的な要件は、エラーレスポンスの本文に詳細を含めることです。Spring Framework は、「HTTP API の問題の詳細」仕様 RFC 7807 (英語) をサポートします。

このサポートの主な抽象化は次のとおりです。

  • ProblemDetail — RFC 7807 問題の詳細の表現。仕様で定義された標準フィールドと非標準フィールドの両方の単純なコンテナー。

  • ErrorResponse — HTTP ステータス、レスポンスヘッダー、RFC 7807 の形式の本文など、HTTP エラーレスポンスの詳細を公開する契約。これにより、例外をカプセル化し、HTTP レスポンスへのマッピング方法の詳細を公開できます。すべての Spring MVC 例外がこれを実装しています。

  • ErrorResponseException — 他の人が便利な基本クラスとして使用できる基本的な ErrorResponse 実装。

  • ResponseEntityExceptionHandler — すべての Spring MVC 例外と任意の ErrorResponseException を処理し、本文でエラーレスポンスをレンダリングする @ControllerAdvice の便利な基本クラス。

レンダリング

RFC 7807 レスポンスをレンダリングするために、任意の @ExceptionHandler または任意の @RequestMapping メソッドから ProblemDetail または ErrorResponse を返すことができます。これは次のように処理されます。

  • ProblemDetail の status プロパティは、HTTP ステータスを決定します。

  • ProblemDetail の instance プロパティは、まだ設定されていない場合、現在の URL パスから設定されます。

  • コンテンツネゴシエーションの場合、Jackson HttpMessageConverter は ProblemDetail をレンダリングするときに "application/json" よりも "application/problem+json" を優先し、互換性のあるメディア型が見つからない場合はそれにフォールバックします。

Spring WebFlux 例外および任意の ErrorResponseException に対して RFC 7807 レスポンスを有効にするには、ResponseEntityExceptionHandler を継承し、Spring 構成で @ControllerAdvice として宣言します。ハンドラーには、すべての組み込み Web 例外を含む ErrorResponse 例外を処理する @ExceptionHandler メソッドがあります。例外処理メソッドをさらに追加し、protected メソッドを使用して例外を ProblemDetail にマップできます。

非標準フィールド

2 つの方法のいずれかで、非標準フィールドを使用して RFC 7807 レスポンスを継承できます。

1 つは、ProblemDetail の「プロパティ」 Map に挿入します。Jackson ライブラリを使用する場合、Spring Framework は ProblemDetailJacksonMixin を登録します。これにより、この「プロパティ」 Map がラップ解除され、レスポンスで最上位の JSON プロパティとしてレンダリングされます。同様に、逆直列化中に不明なプロパティがこの Map に挿入されます。

また、ProblemDetail を継承して、専用の非標準プロパティを追加することもできます。ProblemDetail のコピーコンストラクターを使うと、既存の ProblemDetail からサブクラスを簡単に作成することができます。これは、たとえば、例外の ProblemDetail を再作成する ResponseEntityExceptionHandler などの @ControllerAdvice から、非標準のフィールドを追加したサブクラスを一元的に作成することが可能です。

国際化対応

エラーレスポンスの詳細を国際化することは一般的な要件であり、Spring MVC 例外の問題の詳細をカスタマイズすることをお勧めします。これは次のようにサポートされています。

  • 各 ErrorResponse は、MessageSource を介して「詳細」フィールドを解決するためのメッセージコードと引数を公開します。実際のメッセージコード値は、プレースホルダーでパラメーター化されます。引数から展開される "HTTP method {0} not supported"

  • 各 ErrorResponse は、「タイトル」フィールドを解決するためのメッセージコードも公開します。

  • ResponseEntityExceptionHandler は、メッセージコードと引数を使用して、「詳細」フィールドと「タイトル」フィールドを解決します。

デフォルトでは、「詳細」フィールドのメッセージコードは "problemDetail" + 完全修飾例外クラス名です。例外によっては追加のメッセージコードが公開される場合があり、その場合はデフォルトのメッセージコードにサフィックスが追加されます。次の表に、Spring MVC 例外のメッセージ引数とコードを示します。

例外 メッセージコード メッセージコードの引数

AsyncRequestTimeoutException

(デフォルト)

ConversionNotSupportedException

(デフォルト)

{0} property name, {1} property value

HttpMediaTypeNotAcceptableException

(デフォルト)

{0} list of supported media types

HttpMediaTypeNotAcceptableException

(デフォルト) + ".parseError"

HttpMediaTypeNotSupportedException

(デフォルト)

{0} the media type that is not supported, {1} list of supported media types

HttpMediaTypeNotSupportedException

(デフォルト) + ".parseError"

HttpMessageNotReadableException

(デフォルト)

HttpMessageNotWritableException

(デフォルト)

HttpRequestMethodNotSupportedException

(デフォルト)

{0} the current HTTP method, {1} the list of supported HTTP methods

MethodArgumentNotValidException

(デフォルト)

{0} the list of global errors, {1} the list of field errors. Message codes and arguments for each error within the BindingResult are also resolved via MessageSource.

MissingRequestHeaderException

(デフォルト)

{0} the header name

MissingServletRequestParameterException

(デフォルト)

{0} the request parameter name

MissingMatrixVariableException

(デフォルト)

{0} the matrix variable name

MissingPathVariableException

(デフォルト)

{0} the path variable name

MissingRequestCookieException

(デフォルト)

{0} the cookie name

MissingServletRequestPartException

(デフォルト)

{0} the part name

NoHandlerFoundException

(デフォルト)

TypeMismatchException

(デフォルト)

{0} property name, {1} property value

UnsatisfiedServletRequestParameterException

(デフォルト)

{0} パラメーター条件のリスト

デフォルトでは、"title" フィールドのメッセージコードは "problemDetail.title" + 完全修飾例外クラス名です。

クライアントハンドリング

クライアントアプリケーションは、WebClient を使用する場合は WebClientResponseException をキャッチし、RestTemplate を使用する場合は RestClientResponseException をキャッチし、それらの getResponseBodyAs メソッドを使用して、エラーレスポンスの本文を ProblemDetail や ProblemDetail のサブクラスなどの任意のターゲット型にデコードします。