繁体   English   中英

播放Scala-对Action.async的结果类型感到困惑

[英]Play scala - confusing about the result type of Action.async

我对Action.async的预期结果有些困惑。 这里是用例:从前端,我收到一个JSON进行验证(Foo),我将数据发送给另一个Web服务,然后提取并验证接收到的JSON(Bar case类),我也想对其进行验证。 问题是当我返回结果时,出现以下错误:

type mismatch;
 found   : Object
 required: scala.concurrent.Future[play.api.mvc.Result]

这是我的代码:

case class Foo(id : String)
case class Bar(id : String)

def create() = {
  Action.async(parse.json) { request =>
    val sessionTokenOpt : Option[String] = request.headers.get("sessionToken")
    val sessionToken : String = "Bearer " + (sessionTokenOpt match {
      case None => throw new NoSessionTokenFound
      case Some(session) => session
    })
    val user = ""
    val structureId : Option[String] = request.headers.get("structureId")
    if (sessionToken.isEmpty) {
      Future.successful(BadRequest("no token"))
    } else {
      val url = config.getString("createURL").getOrElse("")
      request.body.validate[Foo].map {
        f =>
        Logger.debug("sessionToken = " + sessionToken)
        Logger.debug(f.toString)
        val data = Json.toJson(f)
        val holder = WS.url(url)
        val complexHolder =
          holder.withHeaders(("Content-type","application/json"),("Authorization",(sessionToken)))
        Logger.debug("url = " + url)
        Logger.debug(complexHolder.headers.toString)
        Logger.debug((Json.prettyPrint(data)))
        val futureResponse = complexHolder.put(data)
        futureResponse.map { response =>
          if(response.status == 200) {
            response.json.validate[Bar].map {
              b =>
              Future.successful(Ok(Json.toJson(b)))
            }.recoverTotal { e : JsError =>
              Future.successful(BadRequest("The JSON in the body is not valid."))
            }
          } else {
            Logger.debug("status from apex " + response.status)
            Future.successful(BadRequest("alo"))
          }
        }
        Await.result(futureResponse,5.seconds)
      }.recoverTotal { e : JsError =>
        Future.successful(BadRequest("The JSON in the body is not valid."))
      }
    }
  }
}

我的功能出了什么问题?

首先,这什么都不做:

    futureResponse.map { response =>
      if(response.status == 200) {
        response.json.validate[Bar].map {
          b =>
          Future.successful(Ok(Json.toJson(b)))
        }.recoverTotal { e : JsError =>
          Future.successful(BadRequest("The JSON in the body is not valid."))
        }
      } else {
        Logger.debug("status from apex " + response.status)
        Future.successful(BadRequest("alo"))
      }
    }

因为您没有捕获或分配结果给任何东西。 等效于执行此操作:

val foo = "foo"
foo + " bar"
println(foo)

foo + " bar"语句没有意义,它什么也做不了。

现在要调试类型推断问题,您需要做的就是将结果分配给事物,并用所需的类型进行注释。 因此,首先将地图的结果分配给以下内容:

val newFuture = futureResponse.map {
  ...
}

现在, newFuture是什么类型? 答案实际上是Future[Future[Result]] ,因为您正在使用map ,然后从中返回一个Future[Future[Result]] 如果要在map函数中返回Future[Future[Result]] ,则必须使用flatMap ,这会将Future[Future[Result]]Future[Result] 但是实际上,在您的情况下,您不需要使用map ,而只需除去所有那些Future.successful调用,因为您实际上没有在该map函数中执行任何需要返回未来的操作。

然后摆脱其他人所说的等待-使用等待意味着阻塞,这首先抵消了使用期货的意义。

无论如何,这应该编译为:

def create() = {
  Action.async(parse.json) { request =>
    val sessionTokenOpt : Option[String] = request.headers.get("sessionToken")
    val sessionToken : String = "Bearer " + (sessionTokenOpt match {
      case None => throw new NoSessionTokenFound
      case Some(session) => session
    })
    val user = ""
    val structureId : Option[String] = request.headers.get("structureId")
    if (sessionToken.isEmpty) {
      Future.successful(BadRequest("no token"))
    } else {
      val url = config.getString("createURL").getOrElse("")
      request.body.validate[Foo].map {
        f =>
        Logger.debug("sessionToken = " + sessionToken)
        Logger.debug(f.toString)
        val data = Json.toJson(f)
        val holder = WS.url(url)
        val complexHolder =
          holder.withHeaders(("Content-type","application/json"),("Authorization",(sessionToken)))
        Logger.debug("url = " + url)
        Logger.debug(complexHolder.headers.toString)
        Logger.debug((Json.prettyPrint(data)))
        val futureResponse = complexHolder.put(data)
        futureResponse.map { response =>
          if(response.status == 200) {
            response.json.validate[Bar].map {
              b =>
              Ok(Json.toJson(b))
            }.recoverTotal { e : JsError =>
              BadRequest("The JSON in the body is not valid.")
            }
          } else {
            Logger.debug("status from apex " + response.status)
            BadRequest("alo")
          }
        }
      }.recoverTotal { e : JsError =>
        Future.successful(BadRequest("The JSON in the body is not valid."))
      }
    }
  }
}

不要Await.result(futureResponse, 5 seconds) 只需按futureResponse返回futureResponse Action.async可以处理它(实际上,它想要处理它,它要求您返回Future)。

请注意,在其他各种代码路径( elserecoverTotal )中,您已经在执行此操作。

如果使用Action.async,则不需要等待结果。 因此,尝试在没有Await.result的情况下按原样返回未来。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM