【问题标题】:How to handle exceptions in a playframework 2 Async block (scala)如何在 playframework 2 Async 块(scala)中处理异常
【发布时间】:2012-06-09 13:17:55
【问题描述】:

我的控制器操作代码如下所示:

  def addIngredient() = Action { implicit request =>
    val boundForm = ingredientForm.bindFromRequest
    boundForm.fold(
      formWithErrors => BadRequest(views.html.Admin.index(formWithErrors)),
      value => {
        Async {
          val created = Service.addIngredient(value.name, value.description)
          created map { ingredient =>
            Redirect(routes.Admin.index()).flashing("success" -> "Ingredient '%s' added".format(ingredient.name))
          }

          // TODO on exception do the following
          // BadRequest(views.html.Admin.index(boundForm.copy(errors = Seq(FormError("", ex.getMessage())))))
        }
      })
  }

我的 Service.addIngredient(...) 返回一个 Promise[Ingredient] 但也可以抛出一个自定义的 ValidationException。当抛出此异常时,我想返回注释代码。

目前页面呈现为 500 并且在我拥有的日志中:

play - 等待承诺,但出现错误:有名称的成分 “测试”已经存在。 services.ValidationException:有名称的成分 “测试”已经存在。

两个问题:

  • 从我的服务中返回此异常是不是一个坏主意,是否有更好/更 scala 的方式来处理这种情况?
  • 如何捕获异常?

【问题讨论】:

  • 前几天修复了一个错误。见this commit。您可以在 Global 对象的 onError 挂钩中处理运行时异常。
  • 但是没有办法在本地捕获异常?
  • 是的,您可以像其他任何异常一样捕获它,如 kheraud 的回答所示。

标签: scala exception-handling validation playframework-2.0


【解决方案1】:

我想说一种纯粹的函数式方法是使用可以保持有效和错误状态的类型。

为此,您可以使用Validation form scalaz

但是如果不需要更多来自 scalaz 的内容(你会 ^^),你可以使用一个非常简单的东西,使用 Promise[Either[String, Ingredient]] 作为结果,并在 Async 块中使用它的 fold 方法。也就是说,map 转换承诺兑现时的价值,fold 转换兑现的价值。

好点 => 没有例外 => 每一件事都是输入检查:-)

编辑

它可能需要更多信息,这里有两个选项:try catch,感谢@kheraud)和 Either。没有放Validation,需要的话问我。 对象应用扩展控制器 {

  def index = Action {
    Ok(views.html.index("Your new application is ready."))
  }

  //Using Try Catch
  //  What was missing was the wrapping of the BadRequest into a Promise since the Async
  //    is requiring such result. That's done using Promise.pure
  def test1 = Async {
    try {
      val created = Promise.pure(new {val name:String = "myname"})
      created map { stuff =>
        Redirect(routes.Application.index()).flashing("success" -> "Stuff '%s' show".format(stuff.name))
      }
    } catch {
      case _ => {
        Promise.pure(Redirect(routes.Application.index()).flashing("error" -> "an error occurred man"))
      }
    }
  }


  //Using Either (kind of Validation)
  //  on the Left side => a success value with a name
  val success = Left(new {val name:String = "myname"})
  //  on the Right side the exception message (could be an Exception instance however => to keep the stack)
  val fail = Right("Bang bang!")

  // How to use that
  //   I simulate your service using Promise.pure that wraps the Either result
  //    so the return type of service should be Promise[Either[{val name:String}, String]] in this exemple
  //   Then while mapping (that is create a Promise around the convert content), we folds to create the right Result (Redirect in this case).
  // the good point => completely compiled time checked ! and no wrapping with pure for the error case.
  def test2(trySuccess:Boolean) = Async {
      val created = Promise.pure(if (trySuccess) success else fail)
      created map { stuff /* the either */ =>
        stuff.fold(
          /*success case*/s => Redirect(routes.Application.index()).flashing("success" -> "Stuff '%s' show".format(s.name)),
          /*the error case*/f => Redirect(routes.Application.index()).flashing("error" -> f)
        )

      }

  }

}

【讨论】:

  • 类型检查解决方案显然更好。感谢您的示例!
  • 没有问题。在这里^^。干杯
  • try-catch 解决方案在 play 2.0.1 中不起作用,可能与 Julien 所指的错误/补丁有关?
  • 很可能是的。他所指的提交帽似乎可以处理 Actions 中的运行时异常。我不知道现在到底是怎么回事。但我猜在扭曲中丢失了异常^^
  • 看起来像 scala 2.10 有一个帮手:blog.richdougherty.com/2012/06/…
【解决方案2】:

你不能在你的异步块中捕获异常吗?

Async {
    try {
        val created = Service.addIngredient(value.name, value.description)
        created map { ingredient =>
            Redirect(routes.Admin.index()).flashing("success" -> "Ingredient '%s' added".format(ingredient.name))
        }
     } catch {
         case _ => {
             Promise.pure(Redirect(routes.Admin.index()).flashing("error" -> "Error while addin ingrdient"))
         }
     }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-08
    • 1970-01-01
    • 2017-05-12
    • 2021-12-27
    • 2013-10-02
    • 1970-01-01
    相关资源
    最近更新 更多