§处理错误
HTTP 应用程序可以返回两种主要类型的错误 - 客户端错误和服务器错误。客户端错误表示连接的客户端做错了什么,服务器错误表示服务器存在问题。
Play 在许多情况下会自动检测客户端错误 - 这些错误包括格式错误的标头值、不支持的内容类型以及对无法找到的资源的请求。Play 在许多情况下也会自动处理服务器错误 - 如果您的操作代码抛出异常,Play 会捕获此异常并生成一个服务器错误页面发送给客户端。
Play 通过 HttpErrorHandler
接口处理这些错误。它定义了两个方法,onClientError
和 onServerError
。
§在 JSON API 中处理错误
默认情况下,Play 以 HTML 格式返回错误。
对于 JSON API,以 JSON 格式返回错误更一致。
Play 提供了一个名为 JsonHttpErrorHandler
的备用 HttpErrorHandler
实现,它将以 JSON 格式返回错误。
要使用该 HttpErrorHandler
实现,您应该在 application.conf
中配置 play.http.errorHandler
配置属性,如下所示
play.http.errorHandler = play.api.http.JsonHttpErrorHandler
§使用 HTML 和 JSON 以及其他内容类型
如果您的应用程序混合使用 HTML 和 JSON,就像现代 Web 应用程序中常见的那样,Play 提供了另一个错误处理程序,它根据客户端的 Accept
标头中指定的偏好委托给 HTML 或 JSON 错误处理程序。这可以通过以下方式指定:
play.http.errorHandler = play.api.http.HtmlOrJsonHttpErrorHandler
对于大多数应用程序来说,这是一个合适的默认错误处理程序选择。
最后,如果您想除了 HTML 和 JSON 之外,还支持其他内容类型的错误,您可以扩展 PreferredMediaTypeHttpErrorHandler
并指定一个自定义错误处理程序,如下所述。
§提供自定义错误处理程序
如果您使用 BuiltInComponents
来构建您的应用程序,请覆盖 httpErrorHandler
方法以返回您自定义处理程序的实例。
如果您使用运行时依赖注入(例如 Guice),则错误处理程序可以在运行时动态加载。最简单的方法是在根包中创建一个名为 ErrorHandler
的类,该类实现 HttpErrorHandler
,例如
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 将默认使用它。
但是,如果您想
- 将其添加到包中;
- 为不同的环境配置不同的错误处理程序;
然后在 application.conf
中添加配置属性 play.http.errorHandler
,指向您的自定义错误处理程序类
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 提供了一个 DefaultHttpErrorHandler
,它具有一些您可以覆盖的便利方法,以便您可以将自定义逻辑与 Play 的现有行为混合使用。
例如,要仅在生产中提供自定义服务器错误消息,而保留开发错误消息不变,并且您还想提供一个特定的禁止错误页面
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 编程
发现文档中的错误?此页面的源代码可在此处找到。在阅读文档指南后,请随时贡献拉取请求。有疑问或建议要分享?前往我们的社区论坛与社区进行交流。