如何重构 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,它可以让您将逻辑放在一个地方,并在 ResultFuture[Result] 中使用您的动作。

对比:https://playframework.com/documentation/2.4.x/ScalaActionsComposition