§エラー処理
HTTPアプリケーションが返すことができるエラーには、主にクライアントエラーとサーバーエラーの2種類があります。クライアントエラーは、接続しているクライアントが何か間違ったことを行ったことを示し、サーバーエラーはサーバーに問題があることを示します。
Playは多くの状況でクライアントエラーを自動的に検出します。これには、不正なヘッダー値、サポートされていないコンテンツタイプ、見つからないリソースのリクエストなどが含まれます。Playは多くの状況でサーバーエラーも自動的に処理します。アクションコードで例外がスローされると、Playはこれをキャッチし、クライアントに送信するサーバーエラーページを生成します。
Playがこれらのエラーを処理するインターフェースは、HttpErrorHandler
です。これは、onClientError
とonServerError
の2つのメソッドを定義しています。
§JSON APIでのエラー処理
デフォルトでは、PlayはHTML形式でエラーを返します。
JSON APIの場合、JSONでエラーを返す方が一貫性があります。
Playは、JSON形式でフォーマットされたエラーを返すJsonHttpErrorHandler
という名前の代替HttpErrorHandler
実装を提供しています。
このHttpErrorHandler
実装を使用するには、application.conf
でplay.http.errorHandler
設定プロパティを次のように設定する必要があります。
play.http.errorHandler = play.api.http.JsonHttpErrorHandler
§HTMLとJSON、その他のコンテンツタイプの両方を使用する
アプリケーションが最新のWebアプリで一般的なHTMLとJSONの両方を使用している場合、Playは、クライアントのAccept
ヘッダーに指定された設定に基づいてHTMLまたはJSONエラーハンドラーのいずれかに委任する別のエラーハンドラーを提供します。これは次のように指定できます。
play.http.errorHandler = play.api.http.HtmlOrJsonHttpErrorHandler
これは、ほとんどのアプリケーションにとって適切なデフォルトのエラーハンドラーの選択です。
最後に、HTMLとJSONに加えて、他のコンテンツタイプのエラーをサポートしたい場合は、PreferredMediaTypeHttpErrorHandler
を拡張し、以下に説明するカスタムエラーハンドラーを指定できます。
§カスタムエラーハンドラーの提供
アプリケーションの作成にBuiltInComponents
を使用している場合は、httpErrorHandler
メソッドをオーバーライドして、カスタムハンドラーのインスタンスを返します。
ランタイム依存性注入(例:Guice)を使用している場合は、エラーハンドラーをランタイム時に動的にロードできます。最も簡単な方法は、ルートパッケージにHttpErrorHandler
を実装するErrorHandler
という名前のクラスを作成することです。例:
import javax.inject.Singleton
import scala.concurrent._
import play.api.http.HttpErrorHandler
import play.api.mvc._
import play.api.mvc.Results._
@Singleton
class ErrorHandler extends HttpErrorHandler {
def onClientError(request: RequestHeader, statusCode: Int, message: String): Future[Result] = {
Future.successful(
Status(statusCode)("A client error occurred: " + message)
)
}
def onServerError(request: RequestHeader, exception: Throwable): Future[Result] = {
Future.successful(
InternalServerError("A server error occurred: " + exception.getMessage)
)
}
}
エラーハンドラーをルートパッケージ(つまり、パッケージなし)に配置し、名前をErrorHandler
にすると、Playはデフォルトでそれを使用します。
ただし、次のような場合、
- パッケージ内に追加する;
- 異なる環境で異なるエラーハンドラーを設定する;
その場合は、カスタムエラーハンドラークラスを指すplay.http.errorHandler
設定プロパティをapplication.conf
に追加します。
play.http.errorHandler = "com.example.ErrorHandler"
クライアントが優先するメディアタイプに対してエラーハンドラーを使用し、別のメディアタイプに対して独自のエラーハンドラーを追加する場合は、PreferredMediaTypeHttpErrorHandler
を拡張できます。
import javax.inject._
import play.api.http._
class MyHttpErrorHandler @Inject() (
jsonHandler: JsonHttpErrorHandler,
htmlHandler: DefaultHttpErrorHandler,
textHandler: MyTextHttpErrorHandler
) extends PreferredMediaTypeHttpErrorHandler(
"application/json" -> jsonHandler,
"text/html" -> htmlHandler,
"text/plain" -> textHandler
)
上記の例では、JSONとHTMLのデフォルトのPlayハンドラーを使用し、クライアントがプレーンテキストを優先する場合(リクエストにAccept: text/plain
がある場合など)、使用されるカスタムハンドラーを追加しています。
§デフォルトのエラーハンドラーの拡張
Playのデフォルトのエラーハンドラーは、すぐに使える多くの便利な機能を提供しています。たとえば、開発モードでは、サーバーエラーが発生すると、Playはアプリケーションでその例外の原因となったコードの部分を見つけてレンダリングしようとします。そのため、問題を迅速に確認して特定できます。本番環境ではカスタムサーバーエラーを提供する一方で、開発環境ではその機能を維持したい場合があります。これを容易にするために、Playは、カスタムロジックをPlayの既存の動作と組み合わせることができる便利なメソッドをいくつか備えたDefaultHttpErrorHandler
を提供しています。
たとえば、開発エラーメッセージをそのままにして、本番環境でカスタムサーバーエラーメッセージを提供する場合、特定の禁止エラーページも提供したいとします。
import javax.inject._
import scala.concurrent._
import play.api._
import play.api.http.DefaultHttpErrorHandler
import play.api.mvc._
import play.api.mvc.Results._
import play.api.routing.Router
@Singleton
class ErrorHandler @Inject() (
env: Environment,
config: Configuration,
sourceMapper: OptionalSourceMapper,
router: Provider[Router]
) extends DefaultHttpErrorHandler(env, config, sourceMapper, router) {
override def onProdServerError(request: RequestHeader, exception: UsefulException) = {
Future.successful(
InternalServerError("A server error occurred: " + exception.getMessage)
)
}
override def onForbidden(request: RequestHeader, message: String) = {
Future.successful(
Forbidden("You're not allowed to access this resource.")
)
}
}
DefaultHttpErrorHandler
の完全なAPIドキュメントを参照して、オーバーライドできるメソッドと、それらをどのように活用できるかを確認してください。
このドキュメントにエラーを発見しましたか?このページのソースコードはこちらにあります。ドキュメントガイドラインを読んだ後、プルリクエストを送信することを遠慮なく行ってください。質問やアドバイスを共有したいですか?コミュニティフォーラムにアクセスして、コミュニティとの会話を始めましょう。