如何重构 PlayFramework Action 和 Async Action 来避免代码重复?
How to refactor PlayFramework Action and Async Action to avoid code duplication?
我有一个方法可以生成验证请求中是否存在用户令牌的操作:
def HasToken[A](p: BodyParser[A] = parse.anyContent)(
f: String => Long => Request[A] => Result): Action[A] =
Action(p) { implicit request =>
request.cookies.get("XSRF-TOKEN").fold {
invalidXSRF
} { xsrfTokenCookie =>
val maybeToken = request.headers.get(AuthTokenHeader).orElse(request.getQueryString(AuthTokenUrlKey))
maybeToken flatMap { token =>
cache.get[Long](token) map { userId =>
if (xsrfTokenCookie.value == token) {
f(token)(userId)(request)
} else {
invalidToken
}
}
} getOrElse noCookie
}
}
然后我可以像这样在我的控制器中使用这个动作:
def method = HasToken(parse.empty) {
token => userId => implicit request => Ok("")
}
但我开始在项目中使用 reactive-mongo 并且所有对数据库的查询 return 都是 Future。我认为真的很好。为了在使用这个 reactive-api 时验证用户,我不得不编写一个新的 Action 验证方法,如下所示:
def AsyncHasToken[A](p: BodyParser[A] = parse.anyContent)(
f: String => Long => Request[A] => Future[Result])(implicit ec: ExecutionContext): Action[A] =
Action.async(p) { implicit request =>
request.cookies.get("XSRF-TOKEN").fold {
Future(invalidXSRF)
} { xsrfTokenCookie =>
val maybeToken = request.headers.get(AuthTokenHeader).orElse(request.getQueryString(AuthTokenUrlKey))
maybeToken flatMap { token =>
cache.get[Long](token) map { userId =>
if (xsrfTokenCookie.value == token) {
f(token)(userId)(request)
} else {
Future(invalidToken)
}
}
} getOrElse Future(noCookie)
}
}
所以,当我需要在我的控制器方法中 return 一个 Future 时,我会这样使用它:
def method() = AsyncHasToken(parse.empty) {
token => userId => implicit request => Future(Ok(""))
}
在尝试重构 HasToken 和 AsyncHasToken 数小时后,我未能产生令人满意的结果。有没有办法把这段代码写得更优雅一些?
我认为这个问题与重构 scala 函数的关系比 Playframework 更相关,但我觉得在通过我的项目编写通用 Actions 和 Async Actions 时我会经常遇到这种模式。
提前致谢。
为此,我会使用 Play ActionBuilder
,它可以让您将逻辑放在一个地方,并在 Result
和 Future[Result]
中使用您的动作。
对比:https://playframework.com/documentation/2.4.x/ScalaActionsComposition
我有一个方法可以生成验证请求中是否存在用户令牌的操作:
def HasToken[A](p: BodyParser[A] = parse.anyContent)(
f: String => Long => Request[A] => Result): Action[A] =
Action(p) { implicit request =>
request.cookies.get("XSRF-TOKEN").fold {
invalidXSRF
} { xsrfTokenCookie =>
val maybeToken = request.headers.get(AuthTokenHeader).orElse(request.getQueryString(AuthTokenUrlKey))
maybeToken flatMap { token =>
cache.get[Long](token) map { userId =>
if (xsrfTokenCookie.value == token) {
f(token)(userId)(request)
} else {
invalidToken
}
}
} getOrElse noCookie
}
}
然后我可以像这样在我的控制器中使用这个动作:
def method = HasToken(parse.empty) {
token => userId => implicit request => Ok("")
}
但我开始在项目中使用 reactive-mongo 并且所有对数据库的查询 return 都是 Future。我认为真的很好。为了在使用这个 reactive-api 时验证用户,我不得不编写一个新的 Action 验证方法,如下所示:
def AsyncHasToken[A](p: BodyParser[A] = parse.anyContent)(
f: String => Long => Request[A] => Future[Result])(implicit ec: ExecutionContext): Action[A] =
Action.async(p) { implicit request =>
request.cookies.get("XSRF-TOKEN").fold {
Future(invalidXSRF)
} { xsrfTokenCookie =>
val maybeToken = request.headers.get(AuthTokenHeader).orElse(request.getQueryString(AuthTokenUrlKey))
maybeToken flatMap { token =>
cache.get[Long](token) map { userId =>
if (xsrfTokenCookie.value == token) {
f(token)(userId)(request)
} else {
Future(invalidToken)
}
}
} getOrElse Future(noCookie)
}
}
所以,当我需要在我的控制器方法中 return 一个 Future 时,我会这样使用它:
def method() = AsyncHasToken(parse.empty) {
token => userId => implicit request => Future(Ok(""))
}
在尝试重构 HasToken 和 AsyncHasToken 数小时后,我未能产生令人满意的结果。有没有办法把这段代码写得更优雅一些?
我认为这个问题与重构 scala 函数的关系比 Playframework 更相关,但我觉得在通过我的项目编写通用 Actions 和 Async Actions 时我会经常遇到这种模式。
提前致谢。
为此,我会使用 Play ActionBuilder
,它可以让您将逻辑放在一个地方,并在 Result
和 Future[Result]
中使用您的动作。
对比:https://playframework.com/documentation/2.4.x/ScalaActionsComposition