【问题标题】:Play 2.5.x (Scala) -- How does one put a value obtained via wsClient into a (lazy) valPlay 2.5.x (Scala) -- 如何将通过 wsClient 获得的值放入(惰性)val
【发布时间】:2016-10-03 16:44:26
【问题描述】:

用例实际上是相当典型的。许多 Web 服务使用您在会话开始时检索的授权令牌,您需要在后续请求中将其发回。

我知道我可以这样做:

lazy val myData = {    
    val request = ws.url("/some/url").withAuth(user, password, WSAuthScheme.BASIC).withHeaders("Accept" -> "application/json")
    Await.result(request.get().map{x => x.json }, 120.seconds)
}

感觉不对,因为所有文档都说我们永远不会等待。

是否有 Future/Promise Scala 风格的方式来处理这个问题?

我找到了.onComplete,它允许我在 Promise 完成时运行代码,但是不使用(可变)var 我认为无法将该范围内的值放入 lazy val 中范围不同。即使使用var,也可能存在时间问题——因此可变变量的弊端:)

还有其他方法吗?

【问题讨论】:

  • 如果您的目标(不是特定于 PlayWS)是从 Future[T] 中获得 T,则将其声明为 lazy val 对我来说没有任何改变:要么您使用 Await (有已知的缺点),或者你不能。
  • 模式是收集这些数据一次并多次使用——这正是lazy val 所暗示的。我正在尝试翻转事物(首先在我的脑海中),这样一旦收到此值,我就会在.onComplete 范围内收集我需要的其余内容并在那里完成处理。考虑到需要做什么以及需要在“哪里”完成(在 Actor 内部),这种方法可能会奏效。
  • 您可以将Future[T] 设为lazy val,但不确定它是否真的有用
  • 仅供参考:上面的代码在我还无法破译的 Actor 内部造成了某种地狱。如果我使用Action.sync {...} 通过控制器的操作调用该代码,如果运行没有问题。但是,如果我尝试通过计时器任务在 Actor 触发器中调用完全相同的代码,那么代码就会停止运行。我没有被锁定我只是在第一次调用 ws.url() 时得到从悬崖上掉下来的代码。计时器继续像“站点”本身一样运行,但 Actor 似乎从未进行实际的网络调用。还不知道如何克服这个...
  • 最后一条评论——stackoverflow.com/a/17612613/2162886——显然@Inject 在字段级别不起作用,除非您的类本身被注入。这是可以原谅的,但它不会在失败时尖叫该死的地狱。我有一个完全静默的空指针——没有堆栈跟踪——什么都没有。日子又一次浪费在 Guice 上……

标签: scala playframework-2.0 future ws-client


【解决方案1】:

不幸的是,没有办法使这个非阻塞 - lazy vals 被设计为同步并阻塞访问它们的任何线程,直到它们完成一个值(内部 lazy val 表示为一个简单的synchronized 块)。

Future/Promise Scala 方法是使用Future[T]Promise[T] 而不是val x: T,但这种方式意味着executionContexts 和maps 的开销很大使用 val 和更优化的资源利用率可能不值得在所有情况下降低可读性,因此如果您在应用程序的许多部分广泛使用该值,则可以将 Await 留在那里。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-27
    • 2014-10-07
    • 2016-08-05
    • 1970-01-01
    相关资源
    最近更新 更多