Scala中Play框架自定义Error Handler未生效问题求助
问题解决方法
你的问题根源在于编译时依赖注入模式下,Play不会读取play.http.errorHandler配置项,必须在自定义的Components类中显式覆盖httpErrorHandler成员才能生效。
修改步骤
- 修改
MyComponents类,替换原有的customErrorHandler定义,直接override框架提供的httpErrorHandler:
class MyComponents(context: Context, system: ActorSystem) extends BuiltInComponentsFromContext(context) with CORSComponents with EhCacheComponents with GzipFilterComponents { ... override val httpFilters: Seq[EssentialFilter] = Seq(corsFilter, requestsCounterFilter, gzipFilter) ... // 显式覆盖httpErrorHandler,替换为自定义实现 override lazy val httpErrorHandler: HttpErrorHandler = new CustomErrorHandler() lazy val myRoutesV1 = new myapp_V1.Routes(httpErrorHandler, myControllerV1) lazy val myRoutesV2 = new myapp_v2.Routes(httpErrorHandler, myControllerV2) lazy val router = new Routes(httpErrorHandler, myRoutesV1, myRoutesV2) }
- 可以删除
application.conf中的play.http.errorHandler = "services.cx.CustomErrorHandler"配置,因为编译时依赖注入模式下该配置不会被框架读取。
原因说明
使用编译时依赖注入(自定义ApplicationLoader和Components)时,Play的核心组件均通过Components类手动构建,而非从配置文件自动加载。BuiltInComponentsFromContext默认提供DefaultHttpErrorHandler作为全局错误处理器,因此必须显式覆盖httpErrorHandler成员才能替换为自定义实现。
你之前仅在Routes构造器中传入customErrorHandler,这仅影响路由层面的错误处理,控制器中抛出的未捕获全局异常仍会使用Components中默认的DefaultHttpErrorHandler。
原始问题背景
已按照Play框架文档实现自定义错误处理器,并在application.conf中添加相关配置,但触发除零异常时,日志显示仍在使用DefaultHttpErrorHandler:
play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[ArithmeticException: / by zero]] at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:255) at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:180)
相关代码及配置详情
自定义错误处理器代码
package services.cx import org.slf4j.LoggerFactory import play.api.http.HttpErrorHandler import play.api.mvc.Results._ import play.api.mvc._ import javax.inject._ import scala.concurrent._ @Singleton class CustomErrorHandler extends HttpErrorHandler { lazy val logger = LoggerFactory.getLogger("myLogger") override def onClientError(request: RequestHeader, statusCode: Int, message: String) = { Future.successful( Status(statusCode)("A client error occurred: " + message) ) } override def onServerError(request: RequestHeader, exception: Throwable) = { logger.error( "onServerError Exception occurred And logged In Error Handler and Exception is " + exception.getMessage ) exception.printStackTrace() Future.successful( InternalServerError("A server error occurred: " + exception.getMessage) ) } }
application.conf配置
play.http.errorHandler = "services.cx.CustomErrorHandler" play.application.loader = MyLoader
自定义ApplicationLoader代码
import org.slf4j.LoggerFactory import play.api.ApplicationLoader.Context import play.filters.cors.CORSComponents import play.api.mvc.EssentialFilter import play.filters.gzip.GzipFilterComponents ... class MyLoader extends ApplicationLoader { def load(context: Context) = { LoggerConfigurator(context.environment.classLoader).foreach { _.configure(context.environment) } val actorSystem = ActorSystem.create() new MyComponents(context, actorSystem).application } } class MyComponents(context: Context, system: ActorSystem) extends BuiltInComponentsFromContext(context) with CORSComponents with EhCacheComponents with GzipFilterComponents { ... override val httpFilters: Seq[EssentialFilter] = Seq(corsFilter, requestsCounterFilter, gzipFilter) ... lazy val customErrorHandler = new CustomErrorHandler() lazy val myRoutesV1 = new myapp_V1.Routes(customErrorHandler, myControllerV1) lazy val myRoutesV2 = new myapp_v2.Routes(customErrorHandler, myControllerV2) lazy val router = new Routes(customErrorHandler, myRoutesV1, myRoutesV2) }
使用环境
- Play框架版本2.6
- Scala版本2.11
- 采用编译时依赖注入
内容的提问来源于stack exchange,提问作者aditt
相关产品推荐
相关产品推荐

