【发布时间】:2018-10-22 06:51:06
【问题描述】:
我找到了我的应用程序没有按照我希望的方式运行的原因,但我不知道如何解决这个问题。总而言之,我的应用程序有一个自定义错误处理程序,如果出现错误,它会被调用。错误处理程序发送json 消息。但是在一个应用程序启动错误场景中(Future 失败),我想Redirect 用户到主页而不是发送json 消息。但这不会发生,因为自定义错误处理程序之前发送json 消息我可以从Future 的recover 发送Redirect。
该应用程序的一个功能是注册验证。用户单击具有令牌的url。单击url 时,会调用verifyUser Action。它进行一些检查(使用使用Futures 的数据库查询)并根据成功或失败发送Redirect 和signup=success 或signup=error 属性(此处不失败取决于数据库中是否存在某些内容或不)。但是,如果Future 失败(我查询了一个不属于数据库架构的错误字段),我想再次Redirect 但它不起作用,因为在recover 之前调用了自定义错误处理程序。如何使我的应用程序重定向?
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)))
)
}
}
当我看到两个调试(一个来自自定义错误处理程序,另一个来自恢复)时,我能够验证问题
server error: request: GET /ws/users/signup/312c9eaf-f27b-43c7-8dac-445a628c3be8, exception: bucket_id is not a column defined in this metadata
Future failed in validateUserSession. Recovering. Returning Internal Server Errorjava.lang.IllegalArgumentException: bucket_id is not a column defined in this metadata
我可以尝试根据自定义错误处理程序中收到的异常进行检查,但我认为它过于通用,可能不是一个好的设计方法。
【问题讨论】:
-
在 singup 错误情况下,您正在执行重定向,您不认为您应该在消息中抛出自定义异常吗?