Play Framework控制器Action中Future执行顺序问题求助
解决Play Framework中Future结果返回异常的问题
首先得说,你的代码里有个明显的语法错误,这是导致你拿到初始值的关键原因——catch块里的case t: Throwable { ... }写法不对,应该是case t: Throwable => { ... },这个错误会让catch块根本无法正确捕获异常,一旦doSomethingAsyncAndGetResponseString()抛出同步异常,fResult就会停留在初始的Future("initial value"),自然拿不到正确结果。
另外,你可能混淆了同步异常和异步异常的处理:如果doSomethingAsyncAndGetResponseString()内部的异步逻辑抛出异常,普通的try-catch是捕获不到的,因为方法已经返回了Future,异常被封装在Future内部,需要用Future的recover方法来处理。
还有,用var来持有Future其实不太符合Scala的函数式风格,我们可以用更优雅的方式来改写代码,同时解决所有问题:
def requestAction(): Action[AnyContent] = Action.async { implicit request => // 先处理调用方法时的同步异常,再处理Future内部的异步异常 val fResult = Try(doSomethingAsyncAndGetResponseString()) // 如果同步调用失败,直接返回失败结果的Future .getOrElse(Future.successful("failed")) // 如果Future内部异步执行失败,也返回失败结果 .recover { case _: Throwable => "failed" } // 等待Future完成后,将结果包装成Ok响应 fResult.map(res => Ok(res)) }
为什么这样能解决问题?
- 同步异常处理:
Try(...)会捕获调用doSomethingAsyncAndGetResponseString()时的同步异常(比如方法一开始就抛出的异常),如果出现异常,getOrElse会直接返回Future.successful("failed")。 - 异步异常处理:
.recover方法会监听Future的失败状态,一旦Future内部的异步逻辑抛出异常,就会将失败的Future转换为成功的Future,值为"failed"。 - Play的异步机制:
Action.async接受一个Future[Result],Play框架会自动等待这个Future完成后再向客户端发送响应,根本不会出现"请求线程提前返回"的问题——你之前的误解可能是因为语法错误导致初始值被返回,误以为是线程提前结束。
如果你一定要保留原来的try-catch写法,至少要先修复语法错误,同时补上异步异常的处理:
def requestAction(): Action[AnyContent] = Action.async { implicit request => var fResult: Future[String] = Future.successful("initial value") try { fResult = doSomethingAsyncAndGetResponseString() } catch { // 这里要改成=>而不是{ case t: Throwable => fResult = Future.successful("failed") } // 别忘了处理Future内部的异步异常! fResult.recover { case _ => "failed" }.map(res => Ok(res)) }
但还是推荐第一种函数式的写法,代码更简洁,也更符合Scala和Play的设计理念。
内容的提问来源于stack exchange,提问作者Zennichimaro
相关产品推荐
相关产品推荐

