API设计:如何从异步XMLHTTP调用处理不同类别的错误?

时间:2009-08-27 04:38:14

标签: web-services vb6 error-handling xmlhttprequest

我有一个遗留的VB6应用程序需要对Web服务进行异步调用。 Web服务提供了search方法,允许最终用户查询中央数据库并查看应用程序内的结果。我正在使用MSXML2.XMLHTTP发出请求,并编写了一个SearchWebService类,它封装了Web服务调用和代码,以便异步处理响应。

目前,SearchWebService会向调用方提出两个事件之一:SearchCompletedSearchFailed。如果调用成功完成,则会引发SearchCompleted事件,其中包含事件参数中的搜索结果。检测到任何类型的故障时都会引发SearchFailed,这可能是由于格式不正确的URL(这可能因为URL是用户可配置的)而导致的低级网络错误,例如“Host not发现“,HTTP错误,如内部服务器错误。它向最终用户返回一个错误消息字符串(如果存在,则从Web服务响应主体中提取;如果响应没有正文,则从HTTP状态代码文本中提取;如果网络错误,则从网络错误代码中转换发生)。

由于各种安全要求,调用应用程序不直接访问Web服务,而是通过在客户站点运行的代理Web服务器访问它,而客户站点又通过VPN访问实际的Web服务。但是,SearchWebService不知道调用应用程序是通过代理访问Web服务:它只是给了一个URL并告诉它发出请求。代理的存在是应用程序级别的要求。

问题在于,从最终用户的角度来看,调用应用程序能够区分低级网络错误与来自Web服务的HTTP错误,并区分代理错误和远程Web服务器错误,这一点很重要。例如,应用程序需要知道请求是否因代理服务器关闭而失败,或者因为代理正在访问的远程Web服务已关闭。在每种情况下都需要向最终用户呈现特定于应用程序的消息,例如“搜索Web服务代理服务器似乎已关闭。代理服务器可能需要重新启动”而不是“代理当前正在运行但是远程Web服务器似乎不可用。请联系(远程Web服务器负责人的姓名)。“我可以直接在SearchWebService类中处理这个问题,但是从这样的泛型类生成这些特定于应用程序的错误消息似乎是错误的(并且该类可能在不需要代理的环境中使用,其中错误消息将不再有意义。)

这种区别对于故障排除非常重要:客户通常可以解决代理服务器问题,但远程Web服务器错误必须由第三方处理。

我在想,解决这个问题的一种方法是让SearchWebService类检测不同类型的错误并在每种情况下引发不同的事件。例如,我可以针对低级网络错误(这表示访问代理服务器时出现问题)而不是单个SearchFailed事件,而是NetworkError事件ConfigurationError类上的无效属性(例如传递格式不正确的URL)和远程Web服务器上发生的错误SearchWebService(暗示代理工作正常但远程服务器返回错误)。

现在我考虑一下,还有一个额外的错误情况:代理服务器可能正常运行,但远程Web服务器已关闭,或者代理服务器配置错误。

使用多个错误事件将不同类别的错误分类为合理解决此问题的方法是什么?对于最后一个场景(代理正在运行,但无法访问远程服务器),我猜我可能必须设置代理才能返回特定的HTTP错误代码,以便客户端可以检测到这种情况(即比500响应)。

最初我保留了单个ServiceError事件,只是在事件中添加了一个额外的SearchFailed参数,但是很快就搞乱了,特别是在没有使用逻辑错误代码的情况下(例如,如果VB6引发“真正的”错误,即如果没有注册XMLHTTP类。

1 个答案:

答案 0 :(得分:1)

我认为我在Java例外中使用的一些想法可能适用于此。

拥有大量不同的异常会变得非常混乱,但我们需要向用户提供足够的详细信息,以便我们不想丢失信息。

因此我有一些特定的例外情况,我想这些事件对应于您的事件:

  • InvalidRequestEvent:用户指定错误信息时使用
  • TransientErrorEvent:在重试可能有效时存在基础结构问题时使用。

我倾向于在我们拥有服务器集群的环境中工作,因此如果用户请求命中一个垂死的服务器,那么如果他重新提交,他可能会得到一个好的,因此从他的角度来看,简单的重试通常是有效的。但是,有时错误在于网络或数据库等服务,在这种情况下,用户需要诊断信息才能向服务台报告。因此,我们需要决定放入异常的额外信息。这是(如果我理解你的话)你的问题。

在InvalidRequestException的情况下,我们打赌会提供有关输入问题的一些信息。它可能是“不匹配的括号”或“表中的未知列CUTSOMER ORDER”。在TransientErrorException的情况下,它可能是“代理服务器已关闭”。

现在,根据您的确切要求,您可能实际上并没有选择将该文本放在Exception中,而是将表示层转换为特定于语言环境的字符串(英语,法语......)的错误编号。

所以Exception可能包含这样的东西(抱歉Java语法,但我希望这个想法很明确):

BaseException {
    String ErrorText;     // the error text itself

    // OR if you want to allow for internationaliation

    int ErrorCode;        // my application specific code, corresponds to text held by the UI
    String[] params;      // specific parameters to be substitued in the error text
                          // CUTSOMER and ORDER in my example above


    int SystemErrorCode;    // If you have an underlying error code it goes here


    String SystemErrorText; // any further diagnoistic you might need to give to 
                            // the user so that they can report the problem to the 
                            // help desk.

    // OR instead of the text (this is something I've seen done)

    int SystemErrorTag;     // A unique id for this particular error problem. 
                            // This server systems will label their message in the
                            // server logs. Users just tell the help desk this number
                            // they don't need to read detailed server error text.

}