如何将每个回调包装在一个地方以改进错误处理

Posted

技术标签:

【中文标题】如何将每个回调包装在一个地方以改进错误处理【英文标题】:How to wrap every Callback in one place to improve error handling 【发布时间】:2013-07-01 09:33:55 【问题描述】:

在我的 GWT 应用程序中,有许多不同的异步调用服务器,使用许多不同的服务。为了更好地处理错误,我想包装我的所有回调,以便我可以在一个地方处理像InvocationExceptions 这样的异常。实现AsyncCallback 的超类并不是一个真正的选择,因为这意味着我必须修改每个异步调用。

RpcServiceProxy#doCreateRequestCallback() 看起来像是要覆盖的方法。很简单。我只是看不到如何让 GWT 使用我的新类。

另一种表述问题的方式是

如何让 GWT 使用我自己的 RpcServiceProxy 子类?

【问题讨论】:

我认为创建一个实现 AsyncCallback 的类是您最简单的选择,即使重构需要一些时间。 【参考方案1】:

为了包装传递给任何RemoteService 的每个AsynCallback<T>,您需要覆盖RemoteServiceProxy#doCreateRequestCallback(),因为在发生RPC 调用之前,每个AsynCallback<T> 都会在此处提交。

以下是执行此操作的步骤:

正如@ChrisLercher 所暗示的,您需要定义自己的代理生成器,以便在每次生成RemoteService 代理时介入。首先扩展 ServiceInterfaceProxyGenerator 并覆盖 #createProxyCreator()

/**
 * This Generator extends the default GWT @link ServiceInterfaceProxyGenerator and replaces it in the
 * co.company.MyModule GWT module for all types that are assignable to
 * @link com.google.gwt.user.client.rpc.RemoteService. Instead of the default GWT @link ProxyCreator it provides the
 * @link MyProxyCreator.
 */
public class MyServiceInterfaceProxyGenerator extends ServiceInterfaceProxyGenerator 
    @Override
    protected ProxyCreator createProxyCreator(JClassType remoteService) 
        return new MyProxyCreator(remoteService);
    

在您的 MyModule.gwt.xml 中,使用延迟绑定来指示 GWT 在生成 RemoteService 类型的内容时使用您的代理生成器进行编译:

<generate-with 
   class="com.company.ourapp.rebind.rpc.MyServiceInterfaceProxyGenerator">
    <when-type-assignable class="com.google.gwt.user.client.rpc.RemoteService"/>
</generate-with>

扩展ProxyCreator 并覆盖#getProxySupertype()。在MyServiceInterfaceProxyGenerator#createProxyCreator() 中使用它,这样您就可以为所有生成的RemoteServiceProxies 定义基类。

/**
 * This proxy creator extends the default GWT @link ProxyCreator and replaces @link RemoteServiceProxy as base class
 * of proxies with @link MyRemoteServiceProxy.
 */
public class MyProxyCreator extends ProxyCreator 
    public MyProxyCreator(JClassType serviceIntf) 
        super(serviceIntf);
    

    @Override
    protected Class<? extends RemoteServiceProxy> getProxySupertype() 
        return MyRemoteServiceProxy.class;
    

确保您的MyProxyCreatorMyServiceInterfaceProxyGenerator 都位于不会被GWT 交叉编译成javascript 的包中。否则你会看到这样的错误:

[ERROR] Line XX: No source code is available for type com.google.gwt.user.rebind.rpc.ProxyCreator; did you forget to inherit a required module?

您现在可以扩展RemoteServiceProxy 并覆盖#doCreateRequestCallback()!在这里,您可以做任何您喜欢的事情,并将其应用于发送到您服务器的每个回调。确保将此类以及您在此处使用的任何其他类(在我的情况下为 AsyncCallbackProxy)添加到要交叉编译的客户端包中。

/**
 * The remote service proxy extends default GWT @link RemoteServiceProxy and proxies the @link AsyncCallback with
 * the @link AsyncCallbackProxy.
 */
public class MyRemoteServiceProxy extends RemoteServiceProxy 
    public MyRemoteServiceProxy(String moduleBaseURL, String remoteServiceRelativePath, String serializationPolicyName,
                                 Serializer serializer) 
        super(moduleBaseURL, remoteServiceRelativePath, serializationPolicyName, serializer);
    

    @Override
    protected <T> RequestCallback doCreateRequestCallback(RequestCallbackAdapter.ResponseReader responseReader,
                                                          String methodName, RpcStatsContext statsContext,
                                                          AsyncCallback<T> callback) 
        return super.doCreateRequestCallback(responseReader, methodName, statsContext, new AsyncCallbackProxy<T>(callback));
    


参考资料:

DevGuideCodingBasicsDeferred.html An example applied to performance tracking

【讨论】:

【参考方案2】:

您要查找的类型可能是RemoteServiceProxy(不是RpcServiceProxy),我假设您应该从覆盖/com/google/gwt/user/RemoteService.gwt.xml 中的默认绑定开始(只需将这些行复制到您自己的.gwt。 xml文件并调整):

<generate-with 
       class="com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator">
    <when-type-assignable class="com.google.gwt.user.client.rpc.RemoteService"/>
</generate-with>

在那里你会找到protected Class&lt;? extends RemoteServiceProxy&gt; getProxySupertype(),你可以覆盖它来返回你自己的RemoteServiceProxyclass。

还没有尝试过,所以这可能需要一些额外的步骤......

【讨论】:

谢谢克里斯,这也是我的方向。我将在我的答案中添加缺少的步骤。【参考方案3】:

通常,GWT 处理异步进程中发生的异常的方式是通过UncaughtExceptionHandlers。

我会使用自己的处理程序来管理这些异常:

GWT.setUncaughtExceptionHandler(new UncaughtExceptionHandler() 
  public void onUncaughtException(Throwable e) 
    if (e instanceof WhateverException) 
      // handle the exception here
            
  
);

使用它你不需要继承任何东西。

【讨论】:

除非我对 GWT 的 RPC 的工作方式完全感到困惑,否则这些异常会被交给 AsyncCallback#onFailure(Throwable),这意味着它们不是“未捕获”的,因此不会到达该处理程序。只有客户端代码中未处理的异常会在那里得到处理,例如小部件中的空指针异常。 您说的很对,只有某些东西使用了未捕获的异常方法,例如我使用的 RequestFactory。乍一看,我认为 RPC 是一样的。【参考方案4】:

如果“一个地方”的意思是“我想用一种方法处理所有错误”,那么我建议要么捕获并扔掉东西直到它们在一个地方,要么创建一个基本上只是发送的EventBus每个错误到。然后,您可以将一个处理程序附加到可以处理所有事情的总线上。

【讨论】:

以上是关于如何将每个回调包装在一个地方以改进错误处理的主要内容,如果未能解决你的问题,请参考以下文章

KnockoutJS 3.X API 第七章 其他技术 异步错误处理

包装 jQuery 的 $.ajax() 方法来定义全局错误处理

AngularJS:如何使用 ngResource 处理成功和错误回调?

如何使用 RxSwift 在一个地方捕获来自两个请求的错误

Go+异常处理

使用 P/Invoke 在托管和非托管回调链上引发异常