![](/img/trans.png)
[英]Action(parser.json) vs Action.async Error, and using concurrent.Execution.Implicits made could not initialize class controllers in Play Scala
[英]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)。
请注意,在其他各种代码路径( else
, recoverTotal
)中,您已经在执行此操作。
如果使用Action.async,则不需要等待结果。 因此,尝试在没有Await.result的情况下按原样返回未来。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.