奇怪的 Java 异常行为

Weird Java Exception Behaviour

我正在使用 Google App Engine with Cloud Endpoints。 我在其中的 Java 异常处理中注意到了一件奇怪的事情。

考虑这个异常堆栈

com.google.api.server.spi.response.ForbiddenException: Unable to find an organization(4)-user(1) match.
    at com.fms.advocacy.api.auth.JwtUser.getUserFromRequest(JwtUser.java:172)
    at com.fms.advocacy.api.user_profile.UserProfileApi.getCurrentUserProfile(UserProfileApi.java:150)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at com.google.appengine.tools.development.agent.runtime.Runtime.invoke(Runtime.java:130)
    at com.google.api.server.spi.SystemService.invokeServiceMethod(SystemService.java:363)
    at com.google.api.server.spi.SystemServiceServlet.execute(SystemServiceServlet.java:113)
    at com.google.api.server.spi.SystemServiceServlet.doPost(SystemServiceServlet.java:71)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
    at com.fms.advocacy.filters.AccessRuleFilter.doFilter(AccessRuleFilter.java:67)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.fms.advocacy.filters.AuthFilter.doFilter(AuthFilter.java:48)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.fms.advocacy.filters.CorsFilter.doFilter(CorsFilter.java:27)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.fms.advocacy.filters.ErrorHandlerFilter.doFilter(ErrorHandlerFilter.java:38)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.api.socket.dev.DevSocketFilter.doFilter(DevSocketFilter.java:74)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)

这里异常是getUserFromRequest方法抛出的。 如您所见,它是从过滤器 ErrorHandlerFilter > CorsFilter > AuthFilter > AccessRuleFilter 链接而来的。

在 ErrorHandlerFilter 过滤器中,我写了一段代码,

 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try { 
            chain.doFilter(request, response);
        } catch (Throwable throwable) { 
            System.out.println("Got " + throwable.getMessage());
        }
    }

因此理想情况下,客户端不应收到任何内容,消息应打印在我的控制台中。但两者都没有发生。相反,客户端收到了以下响应。

{
  "error" : {
    "message" : "Unable to find an organization(4)-user(1) match.",
    "code" : 403,
    "errors" : [ {
      "domain" : "global",
      "reason" : "forbidden",
      "message" : "Unable to find an organization(4)-user(1) match."
    } ]
  }
}

为什么会这样?

抛出的异常在到达 ErrorHandlerFilter 中的 catch 子句之前被捕获。

我不熟悉 google-app-engine,但我想它是由 com.google.api.server.spi.SystemServiceServlet 完成的,因为异常很好地包装在 json 中并且不会进一步传播。

因此,从 ErrorHandlerFilter.doFilter() 方法的角度来看,一切顺利。当 chain.doFilter(request, response); returns 时,json 已经写入 response 的输出流。