如何重构PlayFramework Action和Async Action以避免代码重复?

时间:2015-11-06 08:14:45

标签: scala playframework refactoring

我有一个方法,如果请求中存在用户令牌,则会生成一个Action验证:

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,并且对数据库的所有查询都返回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)
      }
    }

所以,当我需要在我的控制器方法中返回Future时,我会像这样使用它:

def method() = AsyncHasToken(parse.empty) { 
token => userId => implicit request => Future(Ok("")) 
}

在尝试重构HasToken和AsyncHasToken几个小时之后,我还没有能够产生令人满意的结果。有没有办法更优雅地编写这段代码?

我认为这个问题与重构scala函数比Playframework更相关,但我觉得在通过我的项目编写泛型动作和异​​步动作时,我会面对这个模式。

提前致谢。

1 个答案:

答案 0 :(得分:1)

为此我会使用Play ActionBuilder,它可以让您将逻辑保存在一个位置,并对ResultFuture[Result]使用您的操作。

cf:https://playframework.com/documentation/2.4.x/ScalaActionsComposition