我已经找到了我的应用程序无法正常运行的原因,但我不知道如何解决该问题。总而言之,我的应用程序具有一个自定义错误处理程序,如果发生错误,则将调用该处理程序。错误处理程序发送json
消息。但是在一个应用程序启动错误情况下(Future
失败),我想将用户Redirect
转到首页,而不是发送json
消息。但这不会发生,因为自定义错误处理程序先发送json
消息,然后才能从Redirect
的{{1}}发送Future
。
应用程序的一项功能是注册验证。用户单击具有令牌的recover
。单击url
时,将调用url
verifyUser
。它进行一些检查(使用使用Action
的数据库查询),并根据成功或失败而发送带有Future
或Redirect
属性的signup=success
(此处未确定失败)基于数据库中是否存在某些内容)。但是,如果signup=error
失败(我查询了一个错误的字段,该字段不是数据库架构的一部分),我想再次Future
,但是由于自定义错误处理程序在{{ 1}}。如何使我的应用程序重定向?
Redirect
自定义错误处理程序
recover
我能够验证isse,因为我看到了两次调试(一个来自自定义错误处理程序,另一个来自恢复)
val result:Future[Result] = for{tokenOption:Option[UserToken] <- userTokenRepo.findOne(UserTokenKey(UUID.fromString(token))) //generator 1 - get token from database
userOption:Option[User] <- if (tokenOption.isDefined) userRepo.findOne(tokenOption.get.userKeys) else Future.successful(None) //generator2. found token, look for corresponding user to which the token belongs
modifiedUser:Option[User] <- if (userOption.isDefined) confirmSignupforUser(userOption.get) else Future.successful(None) //generator 3. found user and token. Update profile
deletedToken:Option[UserTokenKey] <- if(modifiedUser.isDefined) userTokenRepo.delete(UserTokenKey(UUID.fromString(token))) else Future.successful(None)
}
yield { //check if we have user and token and modified user here. If any is missing, return error else success
println("db query results tokenOption: "+tokenOption+", userOption: "+userOption+" : modifiedUserOption: "+modifiedUser+", deletedToken: "+deletedToken)
if(tokenOption.isDefined && userOption.isDefined && modifiedUser.isDefined && deletedToken.isDefined)
Redirect("http://localhost:9000/home"+";signup=success")//TODOM - pick from config
else
/*TODOM - when redirecting with error, can provide additional info why sign up failed*/
if(tokenOption.isEmpty)
Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
else if(userOption.isEmpty)
Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
else if(modifiedUser.isEmpty)
Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
else //this shouldn't happen. Unexpected
Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
}
result.recover { case x => {
println("Future failed in validateUserSession. Recovering. Returning Internal Server Error" + x)
//before this Redirect, the custom error handler sends json response
Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
}
}
class CustomHttpErrorHandler extends HttpErrorHandler {
def onClientError(request: RequestHeader, statusCode: Int, message: String) = {
println("client error: request "+request+", statusCode: "+statusCode+", message:"+message)
Future.successful(
Status(statusCode)(Json.toJson(JsonResultError(message)))
)
}
def onServerError(request: RequestHeader, exception: Throwable) = {
println("server error: request: "+request+", exception: "+exception.getMessage)
Future.successful(
InternalServerError(Json.toJson(JsonResultError(exception.getMessage)))
)
}
}
我可以尝试根据自定义错误处理程序中接收到的异常进行检查,但是我认为它太通用了,可能不是一个好的设计方法。
答案 0 :(得分:0)
错误可能在创建Future
之前发生,因此代码将引发由默认处理程序处理而不是由Future
捕获的异常。
具体来说,表达式
userTokenRepo.findOne(UserTokenKey(UUID.fromString(token)))
是在当前线程中求值的,因此此代码中的任何异常都不会被捕获,并将调用默认的错误处理程序。
解决方案是在Try
中进行计算,如果有错误,则立即处理错误。
这可能是这样的:
for {
tokenKey <- Future.fromTry(Try(UserTokenKey(UUID.fromString(token))))
tokenOption <- userTokenRepo.findOne(tokenKey)
userOption <- tokenOption.fold(Future.successful)(userRepo.findOne(_.userKeys)) //generator2. found token, look for corresponding user to which the token belongs
modifiedUser <- userOption.fold(Future.successful)(confirmSignupforUser) //generator 3. found user and token. Update profile
...
此代码中的任何异常都将导致Future
代码处理失败的recover
。