我对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."))
}
}
}
}
我的功能出了什么问题?
答案 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)。
请注意,在您的各种其他代码路径(else
,recoverTotal
)中,您已经这样做了。
答案 2 :(得分:0)
如果您使用Action.async,则无需等待结果。因此,如果没有Await.result
,请尝试按原样返回未来