播放scala - 混淆Action.async的结果类型

时间:2015-12-14 09:58:18

标签: json scala playframework-2.0

我对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."))
      }
    }
  }
}

我的功能出了什么问题?

3 个答案:

答案 0 :(得分:4)

首先,这无能为力:

    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,然后从内部返回未来。如果您想在map函数中返回未来,则必须使用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."))
      }
    }
  }
}

答案 1 :(得分:0)

不要Await.result(futureResponse, 5 seconds)。只需按原样返回futureResponse即可。 Action.async可以处理它(事实上,它想要处理它,它需要你返回一个Future)。

请注意,在您的各种其他代码路径(elserecoverTotal)中,您已经这样做了。

答案 2 :(得分:0)

如果您使用Action.async,则无需等待结果。因此,如果没有Await.result

,请尝试按原样返回未来