【问题标题】:Different ways of handling exceptions in Jetty/TomcatJetty/Tomcat 中处理异常的不同方式
【发布时间】:2012-09-18 05:06:43
【问题描述】:

问题的简短版本:什么会导致 Scalatra/(Jetty 或 Tomcat)在不设置请求属性“javax.servlet.error.exception”的情况下将执行传递给 ErrorHandler 的 handle

更长的上下文更多:在我最近加入的一个项目中,ErrorHandlers 的句柄方法具有单独的块,用于处理来自“javax.servlet.error.exception”请求属性和所有其他异常的异常。我们在 Jetty 中运行我们的应用程序,据我了解,Jetty 解开 ServletExceptions 并将它们放在上面的属性中。什么会导致处理非“javax.servlet.error.exception”异常的块被调用呢?或者是多余的,可以去掉?

最初编写代码的人离开了项目。技术栈的其余部分是 Scala 和 Scalatra,如果它有什么不同的话。

  Option(request.getAttribute("javax.servlet.error.exception"))
  .map { 
    exception => exception match {
         //various exceptions handled
   }.getOrElse(handleStatusCode(currentStatus))

编辑:似乎在某些环境中代码在 Tomcat 上运行。

【问题讨论】:

  • 请添加您现在拥有的代码。
  • "什么会导致另一个块被调用?"其他区块?
  • 更新了问题以提供更多信息

标签: tomcat servlets jetty scalatra


【解决方案1】:

我不知道完整的上下文,但我可以想象以下场景。

<servlet-mapping>
  <servlet-name>ErrorPageServlet</servlet-name>
  <url-pattern>/servlet/errorPage/*</url-pattern>
</servlet-mapping>

<error-page>
  <!--unauthorized-->
  <error-code>401</error-code>
  <location>/servlet/errorPage/401</location>
</error-page>

<error-page>
  <!--internal server error-->
  <error-code>500</error-code>
  <location>/servlet/errorPage/500</location>
</error-page>

上面基本上说“对不同类型的 HTTP 错误使用相同的 ErrorPageServlet”。

然后在 servlet 中,您有一个条件来检查是否存在未捕获的异常(查看 "javax.servlet.error.exception" 请求属性),或者如果没有,则可能是导致 HTTP 401 的原因。

【讨论】:

    【解决方案2】:

    这段代码中发生了几个方法调用,相当于如下:

    val a = request.getAttribute("javax.servlet.error.exception")
    val b = Option(a)
    val c = b.map { exception => /* various exceptions handled... */ }
    val d = c.getOrElse(handleStatusCode(currentStatus))
    

    所以,a 只是一个普通的 Java 调用。它将在请求中查找指定的属性,并返回映射到该属性的Objectnull

    对于b,我们调用Option 构造函数将先前的结果包装在一个选项中(这比处理空值更具有Scala 风格)。因此,如果anull,那么b 将是None,否则它将是一个包含a (非空)值的Some 实例。

    在下一行,这个选项被映射成一个新值。如果bNone(即anull),那么c 也将是None。否则,大括号内的逻辑将应用于 b 中包含的值,并将此结果包装在 Some 中返回。

    最后,Option 被解包。如果c 包含某个值,那么这个值本身就是整个块的结果。否则为cNone,则计算handleStatusCode(currentStatus),其结果为整个块的结果。


    因此,我们可以说handleStatusCode 将被调用当且仅当cNone => bNone => anull => 请求没有属性映射到"javax.servlet.error.exception"

    通常应该是这种情况(例如,在每个非错误请求上)。因此,只有当此块出现在检查中时,删除代码才是安全的,例如:

    if (request.getAttribute("javax.servlet.error.exception") != null) {
       ...
       // your posted code
    }
    

    即使你要删除它,你会用什么来代替它? Option 为空时应该是什么结果?由于这个原因,在 Option 上调用 get() 通常是个坏主意;如果你知道它永远不会是空的,你就不需要按照上面的b 行包装它。

    【讨论】:

    • 这不是问题所在。对不起,如果我仍然不清楚。我了解 Scala 代码,问题是关于 Jetty/Scalatra/servlet 集成。
    最近更新 更多