ドキュメント

§エラー処理

HTTPアプリケーションが返すことができるエラーには、主にクライアントエラーとサーバーエラーの2種類があります。クライアントエラーは、接続しているクライアントが何か間違ったことを行ったことを示し、サーバーエラーはサーバーに問題があることを示します。

Playは多くの状況でクライアントエラーを自動的に検出します。これには、不正なヘッダー値、サポートされていないコンテンツタイプ、見つからないリソースのリクエストなどが含まれます。Playは多くの状況でサーバーエラーも自動的に処理します。アクションコードで例外がスローされると、Playはこれをキャッチし、クライアントに送信するサーバーエラーページを生成します。

Playがこれらのエラーを処理するインターフェースは、HttpErrorHandlerです。これは、onClientErroronServerErrorの2つのメソッドを定義しています。

§JSON APIでのエラー処理

デフォルトでは、PlayはHTML形式でエラーを返します。
JSON APIの場合、JSONでエラーを返す方が一貫性があります。

Playは、JSON形式でフォーマットされたエラーを返すJsonHttpErrorHandlerという名前の代替HttpErrorHandler実装を提供しています。

このHttpErrorHandler実装を使用するには、application.confplay.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ドキュメントを参照して、オーバーライドできるメソッドと、それらをどのように活用できるかを確認してください。

次へ:非同期HTTPプログラミング


このドキュメントにエラーを発見しましたか?このページのソースコードはこちらにあります。ドキュメントガイドラインを読んだ後、プルリクエストを送信することを遠慮なく行ってください。質問やアドバイスを共有したいですか?コミュニティフォーラムにアクセスして、コミュニティとの会話を始めましょう。