如何处理Web服务异常

日期: 2008-05-12 作者:张学东 来源:TechTarget中国

  异常是一个事件,它出现在程序执行过程当中,会中断程序指令的正常流程。如果一种方法或者一项Web服务操作出现错误,就会出现异常。引起错误的可能是程序缺陷或者缺少系统资源。典型的问题包括如下:用户输入错误:用户无意中输入了不正确的字符; 物理限制:磁盘空间已满或者溢出可用内存;设备错误:硬件不能正常工作,如无法启用的USB移动硬盘;网络错误:应用服务器试图使用Java数据库连接性(JDC)连接到远程数据库。


  要是被调用方法即提供者出现错误,就必须通知调用程序即使用者。这时,通过编程实现的复杂的异常处理就可以发挥作用:异常出现在调用程序面前,以便从异常中恢复过来。高明的编程人员通常会预料到异常,然后通过编写程序来处理它们;不过,不是所有异常都是能预料到的,也不是所有异常都是能够恢复的。要是没发现异常处理程序,运行系统就会终止、出现不可靠的动作。


  Java和.Net等编程接口拥有一系列广泛、复杂的异常处理功能。开发人员可以使用if-then-else条件结构和try-catch-finally代码块来构建一组丰富的错误处理模式。使用这样一些异常处理模式,开发人员就可以降低程序严重崩溃或者程序突然终止的风险,并且为应用程序添加可靠性。


  在基于Web服务的分布式架构里面,异常处理必须满足额外需求。如今,异常必须能独立于操作系统、编程语言和应用程序进行传送。异常必须提供给使用者,那样它们就随时可以解释; 如果某异常能够恢复,使用者就可以无缝应答Web服务提供者抛出的异常,提供者可能在企业IT部门的里面,也可能在外面。在传送这种异常时,还要关注企业安全。如果异常处理不严格、不认真、不慎重,提供者的Web服务就有可能把内部IT资产的详细信息透露给使用者,或者在堆栈跟踪中泄漏敏感的企业信息。


  为了探讨Web服务的异常处理,本文构建了一个简单的Java类,使用众多的类似方法对两个数进行除法运算。这些方法处理异常的能力各不相同,有的方法完全缺少异常处理机制,而有的方法对许多异常场景拥有显式异常处理结构。如图1所示,我们使用以下组件来准备异常处理测试:


  1.BEA WebLogic Portal 9.2是面向基于Java应用开发的一款应用服务器。安装程序包括BEA Workshop for WebLogic Platform,这是用于迅速构建Web服务的一种IDE。我们决定使用WebLogic,因为它在业界的应用很广泛,而且易于构建Web服务。


  2.Crosscheck Networks SOAPSonar是一个Web服务测试客户程序,它使用WSDL,并且可以为目标Web服务生成功能、性能、互操作性和漏洞等测试。


  未保护的Web服务


  第一个Web服务根本没有防范不利条件的机制。如以下代码所示,这个基本方法读入几个双精度输入,然后除数除被除数,返回作为结果的双精度值。 package   mathservice;
  import javax.jws.*;
  @WebService
  public class DivideWS {
  @WebMethod
  public double nakedDivide(double dividend, double divisor)
  {
   return dividend/divisor;
  }
  }
 
  测试显示了nakedDivide(…) Web方法的行为:正面测试显示,Web服务对输入数字进行了正常除法; 如果输入了零除数,应用服务器就会进行恰当处理,并返回INF值; 如果被除数或者除数什么也没有输入,就会显示详细的堆栈跟踪,还有关于XML处理内部的列表信息,譬如串行化器、SOA服务器协议处理程序和实现平台。


  一般而言,堆栈跟踪信息对Web服务使用者毫无用处,使用者也没有多少办法可以从这样的通用、冗长的异常中恢复过来。这不像一组简单的文档返回代码发送到客户程序、从除以零或者空值异常中轻松恢复过来。发送到客户程序的堆栈跟踪信息不但毫无用处、代码上不可执行,它还可能会把实现细节传送给外部使用者,有可能被人进一步利用。


  防御性Web服务


  下面的代码片显示,防御性Web服务defensiveDivide(…)建立在前一个方法nakedDivide(…)上的基础上,添加了简单的检查机制查看除数是不是零。这可以确保除以零错误不会出现。如果除数是零,该方法就会返回0,那样调用程序就可以从不合适的零除数输入中恢复过来。在这种方法中,编程人员预料到了边界条件,编写防御性代码来处理它。 @WebMethod
  public double defensiveDivide(double dividend, double divisor)
  {
  if (divisor != 0)
   return dividend/divisor;
  else
  return 0;
  }
 
  几个正面和负面测试很快显示了defensiveDivide(…) Web方法的行为:正面测试显示,Web服务对输入数值进行了正常的除法; 如果输入了零除数,不像nakedDivide(…)会在试图进行除法运算后,返回表示无限大的INF值,defensiveDivide(…)返回的是编程人员定义的显式0.0错误值,连除法运算试都不试一下;如果被除数或者除数什么也没有输入,就像nakedDivide()那样,就会显示详细的堆栈跟踪,还有关于XML处理内部的列表信息,譬如串行化器、SOA服务器协议处理程序和实现平台。


  测试结果显示,虽然已经恰当地预料到并处理了除以零场景,但除此之外,防御性错误处理并没有多大作为。不过,编程人员只要避免用坏数据进行计算,就可以让defensiveDivide()比nakedDivide()更有效率。预料意味着可以提高程序效率。


  容器安全的Web服务


  下面,相除方法经过了改动,把字符串值作为输入值,而不是前几个例子中所预料的双精度值。这样,开发人员就可以通过编码来控制输入值的正确性,而不是让方法抛出运行时异常、让容器去处理。如果让容器来处理异常,编程人员就失去了控制权,对编程人员可以处理的预料到的边缘条件而言更是如此。


  字符串除数和被除数先用try-catch代码块转换成双精度数。如果转换不成功,catch代码块就会找出异常,返回零值。转换成功后,检查除数是不是零值; 如果值不是零,运算就成功进行。 @WebMethod
  public double defensiveStringDivide(String dividend, String divisor)
  {
  double dDividend;
  double dDivisor;
  try
  {
   dDividend = Double.parseDouble(dividend);
   dDivisor = Double.parseDouble(divisor);
  }
  catch (Exception e)
  {
   return 0;
  }
  if (dDivisor != 0)
   return dDividend/dDivisor;
  else
   return 0;
  }
 
  测试显示了defensiveStringDivide(…)Web方法的行为:正面测试显示,Web服务对输入数值进行了正常的除法; 如果输入了零除数,像defensiveDivide(…)一样,该方法也是表现正常,不会发送带堆栈跟踪的SOA错误。该方法恰当地返回零值给Web服务使用者; 如果被除数或者除数什么也没有输入,或者输入非数值字符,该方法就会试图转换它,但转换失败,catch代码块会处理异常,然后返回零值。


  defensiveStringDivide()方法比前两种方法来得严格。该方法可以显式防范用户输入随意的非数字值。它可以控制异常处理,并且防止利用非数值输入生成堆栈跟踪。借助防御性编码,编程人员就可以通过容器的异常处理结构来防止信息泄漏。使用这种防御性方法可以降低通过Web服务途径提取程序、解析程序和容器内部的可能性。


  最佳实践


  分布式系统的异常处理很复杂、具有挑战性,这需要全面考虑。由于基于标准的错误传送可使用SOAP错误结构,现在可以跨程序、硬件和系统等界限,使用异常传送和处理机制。不过,由于使用这种基于网络的错误传送机制,就加大了为异常处理合理编写代码的负担。要是没有严谨、慎重的Web服务异常处理机制,最终会把内部组件的细节暴露给外部使用者。这种信息泄漏轻则导致陷入难堪处境,重则会加大公司承担的责任。处理SOA内部异常的一些最佳实践包括如下:


  ● 应当只抛出由使用者使用的异常。
 
  ● 对外型Web服务的所有能够恢复的异常都应当加以清理或者遏制。


  ● Web服务开发人员应当预料到异常,并通过try-catch和if-then-else类型结构,为所有预料到的异常提供合适的处理机制。


  ● 安全管理员应当通过使用SOA/Web服务网关来集中Web服务流,那样通过SOA传送的所有堆栈跟踪都会得到检查和控制,之后SOAP消息才可以离开企业边界。内部Web服务的要求可能不如SOAP错误中出现的对外型Web服务来得严格。


  ● Web服务开发人员应当结合使用try-catch和if-then-else语句用于异常处理。Try-catch应当用做比较通用的异常处理结构,这种情况下不是什么都能预料到的。要记住:try-catch使用过多会给性能带来影响。


  ● 对预料及暴露基于Web服务的复杂、分布式的SOA中的错误条件而言,严格的自动化边界条件测试非常重要。


  ● Java抛出专门的SoapException,它会自动创建SOA错误。开发人员也可以创建SoapException,把定制的异常代码和额外信息放到异常里面。使用这种机制,只要创建定制的SoapException,就可以随时传送简单的错误代码;而不是给使用者带来这种负担:解析由普通的SoapException传送的大型、有时随意的字符串。

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

相关推荐