【问题标题】:GWT - Unable to catch StatusCodeException with UncaughtExceptionHandlerGWT - 无法使用 UncaughtExceptionHandler 捕获 StatusCodeException
【发布时间】:2018-01-10 15:38:01
【问题描述】:

当 Tomcat 会话超时时,我想将我的用户重定向到我的 GWT 应用程序的主页,以便他们可以再次登录。为了强制执行此操作,当用户在会话超时后尝试执行任何操作时,我尝试使用 GWT 抛出的 StatusCodeException -

SEVERE: com.google.gwt.user.client.rpc.StatusCodeException: 0  

为此,我使用以下代码 -

public void onModuleLoad() {
    GWT.UncaughtExceptionHandler uncaughtExceptionHandler = new GWT.UncaughtExceptionHandler() {
        public void onUncaughtException(Throwable e) {
            if (e instanceof StatusCodeException) {
                logger.log(Level.ERROR, "Exception caught!");
                logger.log(Level.ERROR, ((StatusCodeException) e).getStatusCode());
            }
        }
    };
    GWT.setUncaughtExceptionHandler(uncaughtExceptionHandler);
    try {
        // rest of the code in onModule() - I'm expecting any operation to throw StatusCodeException when session times out.
    } catch (RuntimeException ex) {
        uncaughtExceptionHandler.onUncaughtException(ex);
    }
}

这不起作用。 StatusCodeException 没有被代码捕获,而是显示在控制台上。我在这里做错了什么?

这个想法是捕获StatusCodeException并使用它的getStatusCode()方法来找出HTTP错误代码是否为403。如果是,我想使用Window.Location.assign("https://example.com/redirect"); 将他们重定向到登录页面。

【问题讨论】:

  • 你能分享一下你是如何在 onModuleLoad() 中调用服务器的吗?如果您使用的是 AsyncCallback,onFailure 方法在做什么?如果它实际上没有抛出它得到的异常,那么您的未捕获异常处理程序将看不到它。不相关,状态码 0 并不意味着会话已经过期(至少不是来自任何表现良好的服务器......),而是发生了网络错误,浏览器不会告诉客户端代码实际发生了什么( dns、请求超时、请求被拒绝、cors 问题等)。
  • @ColinAlworth 我使用的是AsyncCallback,配置为onFailure(Throwable caught) { logger.error(caught); }。所以,我需要做的就是为UncaughtExceptionHandler 添加throws StatusCodeException 来获取它?

标签: java gwt exception-handling tomcat8 http-error


【解决方案1】:
   onFailure(Throwable caught) { 
       logger.error(caught); 
   }

您的 AsyncCallback.onFailure 正在执行您要求它执行的操作 - 它正在记录错误,但不会抛出错误。由于它没有被抛出,未捕获的异常处理程序不会处理它(它不能被捕获,如果它没有被抛出......如果这有意义的话)。

一种选择可能是您可以使用throw caught 填充该方法,但java 不会喜欢这样。相反,对您的具体问题最简单的答案就是将其传递给处理程序:

   onFailure(Throwable caught) { 
       GWT.getUncaughtExceptionHandler().onUncaughtException(ex);
   }

您还有另一个选择:因为没有 AsyncCallback 会抛出这个,所以将 StatusCodeException 放在 UncaughtExceptionHandler 中似乎有点奇怪。相反,请考虑创建自己的 AsyncCallback 基类,如下所示:

public abstract class NetworkAsyncCallback<T> implements AsyncCallback<T> {
    @Override
    public void onFailure(Throwable t) {
        if (e instanceof StatusCodeException) {
            logger.log(Level.ERROR, "Exception caught!");
            logger.log(Level.ERROR, ((StatusCodeException) e).getStatusCode());
        }
    }
}

现在,当您拨打电话时,您只需传入一个新的NetworkAsyncCallback&lt;T&gt; 并只实现onSuccess。你可以跳过onFailure,如果它要做的只是将异常传递给未捕获的处理程序。或者,如果您有其他逻辑,您可以覆盖 onFailure,处理适当的异常,并调用 super.onFailure(caught) 处理任何其他错误,以便超类处理它。

myServer.getSomeData(param, new NetworkAsyncCallback<Result>() {
    @Override
    public void onSuccess(Result result) {
        //...
    }
    // Skip onFailure, or if you need custom logic, implement it, 
    // and call super only if the exception isn't part of that logic
});

【讨论】:

  • 成功了,谢谢! :) 正如您之前提到的,如果请求失败,StatusCodeException.getStatusCode() 将返回 0 而不是实际的 HTTP 代码。有什么方法可以真正确保错误是由于会话超时引起的?
  • 取决于您如何设置服务器 - 通常,服务器可能应该发回 401(或者可能是 403?)以表明用户无权加载该资源。如果您使用 RPC,您还可以创建一个自定义异常,您的方法使用 throws 声明。我唯一能想到的另一件事(没有看到服务器代码)是您正在使用 CORS 并联系远程服务器,并且服务器没有为初始 OPTIONS“预检”调用发回有效响应。
  • 您对 CORS 的看法是正确的。我正在使用 Google OpenID Connect 进行身份验证。当会话超时并执行操作时,应用程序会尝试点击j_security_check 重定向URL,之后会抛出StatusCodeException;因此错误代码0。一旦我禁用了 CORS,我就能收到StatusCodeException: 400 Bad Request。你会碰巧知道解决这个问题的方法吗?
  • 嗯。错误的请求响应表明您可能不应该首先发出这种请求 - 您是否尝试重用旧链接而不是重新启动身份验证流程或其他什么?如果您自己的服务器正在重定向回 google oauth,您能否改为让它向客户端发送一个错误,并改为检测 that
  • 非常感谢您的帮助!不幸的是,我使用的是OpenID Connect Authenticator for Tomcat,它在容器级别进行身份验证。我必须修改库本身才能进行这种更改。不过,我能够做的是,当StatusCodeException 发生时,使用 JSNI 向基本 URL 发送请求。如果检测到 URL 重定向,我知道服务器不在会话中,可以将我的用户重定向到登录页面。它很粗糙,但有效。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-17
  • 1970-01-01
  • 2011-06-16
  • 1970-01-01
  • 1970-01-01
  • 2021-09-20
相关资源
最近更新 更多