为列表中的每个 URL 发送 WS 请求并将响应映射到新列表

Send a WS request for each URL in a list and map the responses to a new list

我正在 Play with Scala 中开发一个 REST 服务器,它有时需要在一个或多个其他 Web 服务上请求数据。基于这些服务的响应,服务器必须组成一个统一的结果供以后使用。

示例:

www.someplace.com 上的事件 C 需要执行。为了执行事件 C,www.anotherplace.com 上的事件 A 和 www.athirdplace.com 上的事件 B 也必须执行。

事件 C 有一个 Seq(www.anotherplace.com, www.athirdplace.com),我想从中迭代并分别向每个 URL 发送一个 WS 请求,以检查是否执行了 B 和 C。

假设 GET 到这些 URLs returns truefalse

如何收集每个请求的响应(最好合并到一个列表中)并断言每个响应等于 true

编辑:一个事件可以包含任意数量的URL。所以我无法事先知道我需要发送多少 WS 请求。

看看 the documentation 看看你是否可以让他们的例子工作。 尝试这样的事情:

val futureResponse: Future[WSResponse] = for {
  responseOne <- WS.url(urlOne).get()
  responseTwo <- WS.url(responseOne.body).get()
  responseThree <- WS.url(responseTwo.body).get()
} yield responseOne && responseTwo && responseThree

您可能需要解析 WebService 的响应,因为它们(可能)不会 return 布尔值,但您会明白的。

简答

您可以使用 sequence method available on Future 对象。

例如:

import scala.concurrent.Future

val urls = Seq("www.anotherplace.com", "www.athirdplace.com")
val requests = urls.map(WS.url)
val futureResponses = Future.sequence(requests.map(_.get()))

聚合Future

请注意 futureResponses 的类型将为 Future[Seq[WSResponse]]。现在您可以处理结果了:

futureResponses.map { responses =>
  responses.map { response =>
    val body = response.body
    // do something with response body
  }
}

更多详情

来自 sequence 方法的 ScalaDocs

Transforms a TraversableOnce[Future[A]] into a Future[TraversableOnce[A]]. Useful for reducing many Futures into a single Future.

请注意,如果您传递给 sequence 的任何 Future 失败,则生成的 Future 也将失败。只有当所有 Future 都成功完成时,结果才会成功完成。这对于某些用途是有好处的,特别是如果你想同时发送请求,而不是一个接一个地发送请求。