【问题标题】:How to catch exceptions in grails REST controllers如何在 grails REST 控制器中捕获异常
【发布时间】:2015-01-16 12:02:05
【问题描述】:

如果您使用控制器来实现 REST API,您希望处理任何抛出的异常并返回通用或特定格式良好的 REST 响应。

我们不能使用全局错误 URL 映射方法,因为应用程序有许多 API 和接口,响应要求不同,而且我们也不知道会抛出哪种类型的 Grails 的 HTTP 错误代码(例如 don '不知道它是否会是 400、422、500 等)。此外,如果我们使用错误页面映射,我们将无法将相关数据放入 JSON 响应中。

例如这将生成一个 GrailsRuntimeException:

class SomeController {
    def payload = request.JSON
    def someMethod() {
        BigDecimal x = new BigDecimal(payload.notExists)
    }

问题是,似乎无法捕捉到任何抛出的错误。

例如这种方法都不是:

def handleRuntimeException(RuntimeException e) {
      render("some JSON error message")
}

也不是这种方法:

try {
    :
}
catch (GrailsRuntimeException e) {
        render("some JSON error message")
}

有效 - 它永远不会捕获错误。

尝试过 GroovyRuntimeException、Exception、MissingMethodException、Throwable 等

我们能想到的唯一解决方案是不在控制器中做任何工作,在服务中做所有事情,显然我们可以捕获错误。

这种方法:

static mappings = {
    "500"(controller: "error")
}

不想要我们需要有几个原因:

  1. 我们在不同的控制器中有几个不同的 API,它们需要不同的响应格式。
  2. 我们还有 UI 控制器,它们需要显示堆栈跟踪等的默认错误系统。
  3. 我们希望在发生异常的控制器中处理错误,以便我们可以清理,或者至少可以记录或返回只有控制器知道的统计信息。

已决定唯一的方法是将所有代码移动到服务中,并且在控制器中除了传递请求并呈现结果字符串之外什么都不做。即所有参数处理,尤其是数字转换,都在服务中完成。

【问题讨论】:

  • 你提到的两种技术——try/catch 和定义异常处理方法——在我的 2.3.5 应用程序和我的 2.4.4 应用程序中都可以正常工作。您绝对应该能够捕获和处理控制器中抛出的异常。你确定你没有遇到更早的错误吗?
  • 谢谢埃德。即使我们将 try { 作为控制器方法的第一行,并将 } catch (xxx) {...} 作为最后一行,它仍然不会捕获任何错误。它对你有用是一个谜。根据我发现的一些 grails 文档,它说您无法在控制器中捕获错误,您必须使用 url 映射(在我们的案例中这不是解决方案)

标签: grails exception-handling


【解决方案1】:

具有讽刺意味的是,您认为次优的解决方案正是您应该始终做的事情。这不是 PHP - 不要将逻辑放在控制器(或 GSP)中。

服务默认是事务性的,因此它们是放置写入数据库的代码的好地方,因为这应该总是发生在事务中。无论是否是事务性的,它们也非常适合业务逻辑,您可以使用 @Transactional 注释单个方法,以将方法划分为在事务中运行的方法和不在事务中运行的方法,或者将服务拆分为一些是完全事务性的,有些则不是。

如果您将所有与 HTTP 相关的代码保留在控制器中,从 params 进行数据绑定,并调用帮助程序类(服务、域类、标签库等),您将获得良好的关注点分离,并且如果服务层对paramsHttpServletRequest、HTTP 会话等一无所知,那么它很容易在其他 Grails 应用程序甚至非 Grails 应用程序中重用。它们也将更容易测试,因为没有太多相互关联的代码需要被模拟或变得易于测试。

使用这种方法,控制器基本上变成了哑路由器,接受请求,调用助手来完成真正的工作,并委托页面渲染或响应写入,或重定向或转发。

【讨论】:

  • 谢谢伯特。我们所有的业务逻辑都已经在服务中了。我们希望避免将 API 特定代码放入服务中——例如封送和封送原始参数。我们想在控制器中做到这一点。然而,即使是最简单的数字格式错误,抓取参数传递给服务也可能引发无法捕获的异常。
【解决方案2】:

我很晚才回答这个问题,但我认为它可能会帮助人们绊倒并寻找解决方案。

这是我解释Custom exception handling in grails and error responses for RESTfull services的博客之一

希望这可能对某人有所帮助

【讨论】:

    【解决方案3】:

    我使用的是 grails 3.2.4,没有问题,正如您在此处解释的那样。我已将所有业务逻辑移动到服务类中,并通过父控制器特征捕获异常。在这里,我在另一个 ParentExceptionController 特征中处理此异常,该特征由服务类发生此类异常的类实现。示例:

    UserService {
     boolean create(Map params) {
         throw new InvalidParameterException('some message')
      }
    
    UserController implements ParentExceptionController {
     UserService userService
        userService.create(params.userDetails)
      }
    
    trait ParentExceptionController {
     Object handleInvalidParameterException(InvalidParameterExceoption exception) {
      log.error 'log message'
      respond([message: exception.message])
     }
    
    first and second both are working in my case.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-11
      • 1970-01-01
      • 1970-01-01
      • 2018-09-02
      相关资源
      最近更新 更多