2015-12-14 75 views
1

我對Action.async的預期結果有點混淆。這裏的用例是:從前端,我收到一個JSON來驗證(一個Foo),我發送這個數據調用另一個Web服務,然後提取並驗證我想驗證的JSON(Bar case類)。問題是,當我返回一個結果,我有以下錯誤:玩Scala - 混淆Action.async的結果類型

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

不要Await.result(futureResponse, 5 seconds)。按原樣返回futureResponseAction.async可以處理它(事實上,它想要處理它,它需要你返回一個未來)。

請注意,在您的各種其他代碼路徑(elserecoverTotal)中,您已經在執行此操作。

+0

卸下的await讓我的另一個錯誤:'類型不匹配; 找到的:scala.concurrent.Future [對象] 必需:scala.concurrent.Future [play.api.mvc.Result]'。可以肯定的是,從類型系統中,爲什麼我的函數(沒有等待)沒有很好地輸入? – alifirat

+0

'futureResponse'的類型是什麼?也許你在那裏嵌套了Futures,並且需要一些'flatMap'。最後,你需要結束'Future [結果]'。 – Thilo

+0

futureResult的類型:'scala.concurrent.Future [play.api.libs.ws。WSResponse]' – alifirat

0

如果使用Action.async,則不需要等待結果。因此,試圖返回未來,而不做Await.result

+0

刪除await讓我另一個錯誤:'type mismatch; 找到的:scala.concurrent.Future [對象] 必需:scala.concurrent.Future [play.api.mvc.Result]'。 – alifirat

3

首先,這是什麼都不做:

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函數。

然後擺脫其他人所說的等待 - 使用await意味着封鎖,這首先否定了使用期貨的觀點。

無論如何,這應該編譯:

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.")) 
     } 
    } 
    } 
} 
+0

謝謝你的回答和解釋。 – alifirat