scala - 尝试解析 Future 响应时出了什么问题?

标签 scala http playframework response future

我有一个函数可以通过 ajax 请求获取 token 。当 token 有效时,它将返回目录列表的响应。

def all = Action.async(parse.json) {
  implicit request => tokenForm.bind(request.body).fold(
    formWithErrors => Future.successful(BadRequest(formWithErrors.toString)),
    form => checkToken(form.token).map(token => {
      val directories = Directories.all.map(directory => {
        Json.toJson(directory)
      })
      Ok(Json.obj("status" -> {if (token.get.id.getOrElse(0) >= 1) true else false}, "message" -> {if (token.get.id.getOrElse(0) >= 1) Json.toJson(directories) else "Invalid token"}))
    })
  )
}

当我运行上面的代码时它说 [As ^ sign indicate the position the error found]

No Json serializer found for type scala.concurrent.Future[play.api.libs.json.JsValue]. Try to implement an implicit Writes or Format for this type.
Ok(Json.obj("status" -> {if (token.get.id.getOrElse(0) >= 1) true else false}, "message" -> {if (token.get.id.getOrElse(0) >= 1) Json.toJson(directories) else "Invalid token"}))
                                                                                                                                            ^

最佳答案

这是我想出来的

def all = Action.async(parse.json) {
  implicit request => tokenForm.bind(request.body).fold(
    formWithErrors => Future.successful(BadRequest(formWithErrors.toString)),
    form => for {
      (token, directories) <- checkToken(form.token) zip Directories.all
    } yield {
      val isTokenValid = token.isDefined
      val responseBody = Json.obj(
        "status" -> isTokenValid, 
        "message" -> {
          if (isTokenValid)
            Json.toJson(directories)
          else
            "Invalid token"
        }
      )
      Ok(responseBody)
    }
  )
}

假设 checkTokenDirectories.all 返回 Future

您的函数需要返回 Future[Result]。折叠时,第一个分支是正确的

formWithErrors => Future.successful(BadRequest(formWithErrors.toString))

然而,在第二个分支中,您似乎通过调用 Directories.all 开始了一个新的 Future,并且您希望将其序列化并作为 json 返回。 Future[JsValue] 没有序列化器,因为这毫无意义,它必须阻塞才能获得结果。您需要以某种方式获取 checkToken(form.token)Directories.all 的值。

你可以像我上面那样做,或者像这样:

form => {
  val futureToken = checkToken(form.token)
  val futureDirectories = Directories.all

  for {
    token <- futureToken
    directories <- futureDirectories
  } yield {
     // same code as above
  }
}

请注意,如果您要内联 futureTokenfutureDirectories,它们将被串行执行。

另请注意,您将目录列表转换为 json 两次。

曾经在这里

val directories = Directories.all.map(directory => {
  Json.toJson(directory)
})

假设 Directories.all 返回 Future[List[Directory]],那么当您使用 map 时,您传递的函数对 List[Directory] 所以变量应该命名为 directories 而不是 directory。它会工作,轻松 Play 任何可转换为 json 的列表,无需手动执行。

第二次来这里

Json.toJson(directories)

关于scala - 尝试解析 Future 响应时出了什么问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38026615/

相关文章:

scala - scala 中具有不同类型参数的 Varargs

scala - 为什么Spark with Play的 “NoClassDefFoundError: Could not initialize class org.apache.spark.SparkConf$”失败?

java - 如何将列表呈现为模板?

scala - Play 框架应用程序中的环境特定配置

java - URL中的方括号导致Tomcat异常

scala - 使用 sbt 从代码启动 scala repl 循环

scala.concurrent.blocking - 它实际上做了什么?

http - 在哪里可以找到超文本 ORB 间协议(protocol) (HTIOP) 的规范?

http - Docker如何将请求(curl - get,post)一个容器发送到另一个容器

json - 如何在 GET 请求中发送结构