我是 play2.0-Scala 初学者,必须调用多个 Web 服务来生成 HTML 页面。
阅读 The Play WS API 后页面和非常有趣的article from Sadek Drobi我仍然不确定实现此目标的最佳方法是什么。
本文展示了一些代码片段,作为 Play 初学者,我无法完全理解这些代码片段。
第 4 页上的图 2:
val response: Either[Response,Response] =
WS.url("http://someservice.com/post/123/comments").focusOnOk
val responseOrUndesired: Either[Result,Response] = response.left.map {
case Status(4,0,4) => NotFound
case Status(4,0,3) => NotAuthorized
case _ => InternalServerError
}
val comments: Either[Result,List[Comment]] =
responseOrUndesired.right.map(r => r.json.as[List[Comment]])
// in the controller
comment.fold(identity, cs => Ok(html.showComments(cs)))
最后一行 fold
的作用是什么? comment
应该是comments
吗?我没有将最后一条语句分组到 Async
block 中吗?
图 4 显示了如何将多个 IO 调用与单个 for
表达式组合起来:
for {
profile <- profilePromise
events <- attachedEventsPromise
articles <- topArticlesPromise
} yield Json.obj(
"profile" -> profile,
"events" -> events,
"articles" -> articles )
}
// in the controller
def showInfo(...) = Action { rq =>
Async {
actorInfo(...).map(info => Ok(info))
}
}
我如何使用这个片段? (我对 for 表达式后面的额外的 -}
感到有点困惑。)
我应该写这样的东西吗?
var actorInfo = for { // Model
profile <- profilePromise
events <- attachedEventsPromise
articles <- topArticlesPromise
} yield Json.obj(
"profile" -> profile,
"events" -> events,
"articles" -> articles )
def showInfo = Action { rq => // Controller
Async {
actorInfo.map(info => Ok(info))
}
}
组合图 2 和图 4 中的片段的最佳方法是什么(错误处理 + IO 非阻塞调用的组合)? (例如,如果任何被调用的 Web 服务产生错误 404,我希望产生错误 404 状态代码)。
也许有人知道在 play 框架中调用 Web 服务的完整示例(在 play 示例应用程序或其他任何地方找不到示例)。
最佳答案
我不得不说,这篇文章在图 2 中显示的示例中是错误的。Play 2.0 中不存在 focusOnOk
方法。我假设这篇文章的作者当时使用的是 Play 2 的预发行版本。
关于评论
,是的,应该是评论
。语句中的 fold
正在对 Either
进行操作。它需要 2 个函数作为参数。第一个是左值时要应用的函数。第二个是如果它是正确值则应用的函数。更详细的解释可以在这里找到:http://daily-scala.blogspot.com/2009/11/either.html
所以这条线的作用是。如果我有左值(这意味着我得到了不需要的响应),请应用内置的 Identity 函数,它只会返回该值。如果它具有正确的值(这意味着我得到了 OK 响应),请创建一个以某种方式显示评论的新结果。
关于Async
,它实际上并不是异步的。 focusOnOk
是一个阻塞函数(Play 1.x 的旧 Java 时代的残余)。但请记住,这不是有效的 Play 2 代码。
对于图 4,尾随的 }
实际上是因为它是图 3 中内容的部分替代。而不是众多的 promise flatMap
。你可以做for comprehension反而。另外,我认为它应该是 userInfo(...).map
而不是 actorInfo(...).map
。
Play documentation您链接到的实际上已经向您展示了一个完整的示例。
def feedTitle(feedUrl: String) = Action {
Async {
WS.url(feedUrl).get().map { response =>
Ok("Feed title: " + (response.json \ "title").as[String])
}
}
}
将获取 feedUrl 中的任何内容,然后将其映射
以对 response
执行某些操作,该响应具有可以检查的 status
字段看看是 404 还是其他什么。
为此,链接文章的图 3 和图 4 应该为您提供一个起点。所以你会得到类似的东西,
def getInfo(...) : Promise[String] = {
val profilePromise = WS.url(...).get()
val attachedEventsPromise = WS.url(...).get()
val topArticlesPromise = WS.url(...).get()
for {
profile <- profilePromise
events <- attachedEventsPromise
articles <- topArticlesPromise
} yield {
// or return whatever you want
// remember to change String to something else in the return type
profile.name
}
}
def showInfo(...) = Action { rq =>
Async {
getInfo(...).map { info =>
// convert your info to a Result
Ok(info)
}
}
}
关于web-services - 从 play 2 调用多个 Web 服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12246541/