CIO信息化管理 |
|
| 按行业筛选 |
|
|
| 按产品筛选 |
|
|
| |
查看本类全部文章 |
| |
|
|
|
Web服务中五个最常见的错误 |
|
作者:Paul Ballard |
|
在这篇文章中,我们将会讨论企业在开发Web服务时最容易犯的五个错误。需要注意的是,这些错误并不是逻辑或语法错误,所以不会有编译器错误提示你哪里错了或者哪里应该抛出异常。这篇文章中描述的问题出现在体系结构方面,而不是技术本身。要想避免这些问题,你必须从一开始就关注它们,因为如果在服务被部署后再来解决这些问题的话会变得相当困难。
1.错误一:使用 .NET的特定类型。
Web服务最基本的理念就是创建一个应用程序逻辑层,该逻辑层能够被其他人和其他应用程序在任何时间任何地点进行访问,而不管使用的技术是什么。也就是说,即使你的Web服务是用.NET构建的,但是客户端的访问技术很可能是非.NET技术。要真正达到这种和Web服务无缝结合工作的能力,最重要的一点是不要在代码中包含服务,至少不要直接的包含。要使得Web服务能够和任何技术都能无缝结合,必须保证数据约束的定义必须依靠XML Schema中提供的数据类型来实现,而不是通过.NET构架中的数据类型来实现。因为如果你使用.NET特定的类型作为参数为Web服务返回值时,产生的XML可能无法和Java或其他技术一起工作。
也许你看见过一个很简单的演示,告诉你如何创建一个简单的Web服务并且进行数据库查询,然后以ADO.NET Dataset的方式返回数据。一个Dataset是一个完全脱机版的关系数据结构,它包括表、键和关系,所以它并不是跨越物理界限传输数据完美的对象。从Web服务的角度看来,表面现象有时会欺骗你的眼睛。
在Web服务中将一个Dataset作为结果或参数会产生一系列的问题。第一个问题可能会发生在WSDL中。WSDL(Web服务描述语言)是一个用以定义客户端如何与你的服务发生联系的XML Schema,并告诉客户端你的服务使用什么参数和返回什么类型的值。WSDL通常被用来产生客户端的代理类,所以它的描述越丰富,客户端越容易和我们的服务进行互动。
让我们来看看一个简单的使用了一个返回Dataset的Web服务,它包含了一行Northwind顾客表的数据。图1显示了这个Web服务的WSDL。请特别注意一下被标识出的GetCustomerResponse元素。
图1 因为Dataset的结构只有在运行时间才能被系统了解,所以这里无法通过WSDL来描述它的内部结构。为了适应这种情况,GetCustomer方法返回的值(GetCustomerResponse元素)拥有两个元素,一个是在对象类型中合法的任意类型()元素;一个XML Schema(),用于在运行时描述返回的Dataset的结构。这和一点和接下来的过程中需要绑定的Web服务是一致的。
因为客户端开发人员不清楚你的方法返回的对象结构是什么,所以他们无法生成一个非常有用的代理。这些客户端能够继续使用你的Web服务,但是他们需要解析你返回的XML文档并找到他们想要寻找的信息。Web服务类型无关的特点被抛到了脑后,任何非.NET的客户端开发人员在使用你的服务时会感到极其困难。
现在你可能会问:“如果WSDL没有定义一个Dataset的返回类型,那么这些示例是如何工作的呢?”答案是XML在运行时间返回。图2显示了在调用我们的GetCustomer方法后的结果。
点击看大图 请注意那个NewDataSet元素被赋予了一个额外的由微软制定的属性,“IsDataset”。这个是Visual Studio的使用技巧之一,表示结果必须被反序列化为一个Dataset。当然,你如果是通过一个非.NET的客户端,例如J2EE来调用这个Web服务的话,这个属性将没有任何意义。
除此之外,还有一个在Web服务之间传输Dataset遗留的问题,那就是被传输数据的过于复杂,导致所需信息埋藏过深。图2中的XML只描述了只有一个表的Dataset的结构,一旦你再添加表、关系、或者键,那么这个Schema会变得极其复杂和庞大。实际上只要用户进行了真正的数据返回操作,这个文件就会增长得非常迅速。请记住,你和Web服务之间交换的数据量越大,你的响应就会变得越慢。
Dataset很可能是Web服务中被使用得最广泛的.NET特定类型,但却不是唯一的特定类型。对于.NET开发人员来说,他们很希望通过使用.NET框架提供的高级功能或类,但是如果无缝结合工作能力是你的目标的话,那么你就需要抑制这种想法。要想达到最大程度的无缝结合和技术无关的工作能力,关键是确保所有被用作参数和返回值得类型都是使用XML Schema基础类型进行描述的。你可以在http://www.w3c.org/TR/xmlshema-2/中找到更多关于XML Schema内建类型的资料。
2.错误二:没有充分利用ASP.NET的优点
部署Web服务最大的一个瓶颈是它的性能,任何能够增强性能的努力都值得去尝试。以.NET框架开发的Web服务是通过ASP.NET来部署的,所以Web服务和其他任何ASP.NET的应用程序一样,具有一些和ASP.NET相关的强大功能,我们要充分使用和挖掘这些功能。对于性能来说,最重要的两个功能是Caching和SessionState。
Web服务能够使用两种类型的Caching。第一个也是较为简单的一个是输出Caching。输出Caching能够将一个服务方法请求返回的结果存储在服务器的缓存中,这样如果在以后再遇见使用相同参数的方法请求,则直接从服务器的缓存中获取结果,不再真正调用服务方法,这样就能够减少数据查询、逻辑处理的系统开销。当服务方法的参数改变时,系统会将一条标识有过期时间的新纪录加载到服务器的缓存之中,以方便在一定的时间内被再次利用。要使用这个功能,只需在你的WebMethodAttribue类中增加“CacheDuration”属性就可以了,下面是一个简单的示例,表示服务器会将某个服务方法返回的结果缓存120秒。
_
Public Function GetQuote() As Quote
此外,你也可以在不同的请求之间使用应用程序缓存特定的数据。通常情况下,被缓存的都是一些频繁使用但是不经常改动的数据。
要说明这个问题,我们首先构建一个虚拟的服务,用于获取股票的报价。服务中有一个功能,用于接收用户输入的某个公司的名称,然后查询该公司股票的信息,并将这个信息返回给用户。用户会经常调用这个功能,但是它的数据改变频率却很低。在这样的情况下,我们可以在服务开始时对数据库进行一次查询然后返回一个包含了所有公司和相关股票标识信息的数组,并将这个数组存储在缓存中,最后将过期时间设置为24小时。这样一来,当用户对某个公司的股票信息进行查询时,就不用再兜圈子般的去查询数据库了,直接查找我们存储在缓存中的数组就可以返回所需要的股票信息。图3显示了部署这种缓存所使用的代码。
点击看大图 除此之外,Web服务还能够使用内建的SessionState持久性,该功能由ASP.NET与非处理过程的状态服务器以及SQL Server数据库服务器协同工作来提供。要启用这个功能,只需在WebMethod属性中添加“EnableSession=True”即可。这种方法特别适合于在不同请求间存储客户端特定的信息。例如,继续开发我们的股票分析服务,假设我们的Web服务允许客户根据需要创建一个自定义的股票列表。当客户端的发出一次请求,返回这个为某个特定用户存储的股票列表时,我们在将这个列表返回给用户之前,先把它存储在SessionState中。这样一来,如果用户没有发出一个获取其它列表的新请求的话,我们就可以修改获取股票信息的代码,让服务方法直接从SessionState中获取股票列表,这样做能够极大程度的提高数据更新的速度。图4显示了使用SessionState方法的代码示例。ASP.NET使用客户端cookie为SessionState识别独立的客户端session状态,所以要使用这个功能,你需要在客户端的机器上做些工作。在.NET中这个工作非常简单,我们只需要创建一个新的CookieContainer对象来存放从服务接受到的cookie就可以了。下面是需要用到的客户端代码。
myService.CookieContainer = New System.Net.CookieContainer
尽管使用SessionState能够很大程度的提高性能,但它也在某种程度上破坏了“服务”的定位,因为服务应该是无状态的。还有重要的一点,你必须记住并非所有的客户端都会接受你的cookie。抛开这两点不谈,SessionState对性能的提升是非常显著的,只要你遵循下面几个原则,就能合理的使用它:
原则1:任何使用SessionState的WebMethod都必须有一个相应的无状态版本。
原则2:出于对服务透明性的考虑,你应该以某种形式为你的状态方法命名,以便让客户端的开发人员知道他能够使用SessionState。
3.错误三:请求的数量不够
如果你曾经独自追踪你的Web服务在整个公司的流程,会发现一件事是确定的,你只希望进行一次这样的流程,就能返回所有你需要的信息。这个道理和我们在去超市之前先理出一份要购买物品的清单是一样的,我们不希望为买某一个商品都逛一次超市。对于Web服务来说,如果一个请求需要跨越不同的物理区域,总会带来一些性能的降低或者网络流量的增加。
你的Web服务应该被设计为在一次请求时能够进行最多的工作。并且确保客户第一次必须访问的某个地方的功能点一定有值得客户这么去做的原因。为了解释这个问题,我们还是回到刚才股票服务的那个例子。
你很可能已经看见了一些示例告诉你如何发送股票信息然后获取该股票在当前市场的价格,并且实现起来非常简单。但如果你一次想查看十个股票的价格呢?如果使用这个Demo版的Web服务,你需要在服务器之间进行十次数据交换,如果换作是一个大超市,你愿意这样走十次来获取十个不同的商品吗?
为了追求更好的性能,请将一些较小的请求点合并为一个较大的单一请求。在我们股票信息服务的例子中,我们可以简单的将所有的股票信息存放在一个string类型的数组中,然后从该方法返回关于股票报价的数组。图5显示了应用GetQuotes方法的代码。如果情况更复杂一些,那么你的Web服务可能会开始看起来像一个请求-代理模式,实际上很多Web服务都是基于这种模式构建的。每个请求都包含了一个或多个较小的请求,返回的值则被聚合成一个单一的响应,并返回到客户端。但必须注意一点,这么做会很快地增加某个服务的性能花销,尤其是这个服务有一个很通用的用于接收和返回信息的接口时。而且我们也会遭遇某种情况,客户端的应用程序无法创建有用的代理,并且依赖于外部文档来协同工作。你需要找出请求聚合与被复杂性所影响的性能之间的平衡点,对于一个应用程序构架师来说,这是一个必做的功课,你需要通过一些不同的测试用例才能获得比较好的结果。
4.错误四:仅仅将Web服务用于数据访问
这样的错误来自于对Web服务基本概念的错误理解。很多构架师和开发人员将Web服务看作是一种共享数据的手段。这种概念的混淆是能够理解的,就连微软自己也用一些“功能增强”来搅这滩浑水,例如在SQL Serve 2005中标榜的只需简单的几下鼠标点击就可以通过Web服务访问存储过程等功能,这些都是让用户产生概念混淆的原因。但是这并不是一个好现象,因为错误的理解会导致一个糟糕的应用程序设计。
Web服务并不仅仅提供对数据的访问,它们提供了对整个企业及企业相关业务信息的访问。不同规模的组织,从小办公室到整个集团,都是被该组织的业务特长所定义和识别的。你不会为了银行账户的事情而去星巴克咖啡厅,而美国银行也不会供应你Lattes咖啡。但是企业之间往往又想和其他企业共享其业务,例如星巴克也许会通过美国银行来提供用信用卡购买Lattes咖啡的服务。这种业务共享的方式意味着星巴克不必关心信用卡的处理过程,他只要专注与生产他的咖啡就可以了。
组织如何部署它们的业务技术呢?一种方法是开发一个自由的应用程序,这样可以对该公司的业务技术进行增强、改进或自动化。这就是Web服务和服务定位介入的背景。通过提供对这些应用程序访问的接口给其他的组织,这些企业组织将自己的业务技术进行了有效的共享。
有一个很好的例子能够说明Web服务提供的是功能,而不是数据,它就是Google用于搜索web页面的Web服务。如果这样的服务仅仅返回结果,它的作用会有多大呢?如果这个Web服务把上百万的web页面信息返回给你,但是你必须自己在其中查找想要的页面呢?Google很好的应用和扩展了它们在搜索网络方面的业务技术,而这些技术正是他们提供的Web服务的价值。
当你开发自己的Web服务时,请记住你的客户需要从你的服务获得的是你的业务技术,而不是你的数据。你需要对任何仅仅查询和返回数据的Web服务提出质疑并进行检查,因为如果出现了这种情况,很可能是因为在你的服务业务逻辑出现了错误的定位,这样会导致你的客户不得不重新构建你的业务技术,那样就失去Web服务的意义了。
5.错误五:信任客户端应用程序
一个Web服务的作用仅仅是简单的允许外部访问你的业务技术,反过来说,保护你的业务隐私和数据集成性也是一个Web服务的职责。很多情况下一个Web服务是与使用它的用户界面接口一起开发的,相对于应用程序来说,Web服务往往扮演着“后台”的角色,而安全性的问题就留给了用户界面接口。这样的做法将会带来安全隐患,如果你仅仅把安全问题应用在用户接口之上,这将使得你的Web服务变得非常容易受到攻击,而你的业务完整性也会受到威胁。
解决这个问题的办法是从两个方面来考虑问题,当你思考和设计时,都要考虑客户端用户接口的安全性和Web服务本身的安全性。每个部分都需要应用一定的安全技术,包括认证、审核、数据加密等等。请时刻牢记,其他组织也会在你的Web服务后台之上构建自己的应用程序,所以你必须保证Web服务的安全性,然后再来谈论其他的问题。
安全性是一个很宽泛的主题,其内容大大超出了本文所能描述的范围,但是在这里我可以给你提一些关键的注意事项,这样你在查找相关信息的时候能够做到有的放矢。
你应该做出这样的假设,即你不能信任通过向Web方法输入信息然后获取到的任何数据。Web服务的宿主是ASP.NET,所以它和其他任何ASP.NET应用程序一样,都有遭受攻击的可能,例如SQL注入式攻击、拒绝服务攻击、延迟攻击等等。幸运的是你能够采取很多应对策略和措施来保护你的Web服务不受这些攻击的伤害。
被返回的数据同样需要保护。如果你担心数据在网络传输过程中的完整性问题,那么最简单的方法是采用SSL在客户端和服务器端之间进行加密。你也可以通过不返回动态定义对象(例如Dataset和XmlDocument)的方式,减少来自于SQL注入式攻击的威胁。
审核机制是一项重要但是通常容易被忽视的安全性功能。通过构建对Web服务使用情况的追踪,可以帮助你了解恶意访问的情况并及时对攻击做出响应。例如系统在遭遇清除数据这样的恶意操作会给管理员发出一个提示信息,或直接将该用户对某种服务的访问权限禁用。通过部署基于使用情况的审核机制,可以极大程度地消除拒绝式攻击的影响。
从整个系统构架的角度来看,避免在部署Web服务之后出现安全问题的关键是从一开始就把安全性放在需要考虑的问题列表之中,千万不要掉以轻心的认为只要客户端采用了一定的安全措施就足够了。
结论
Web服务为构建跨地域、跨组织结构的应用程序提供了一个空前的提升和进步。Visual Studio.NET和.NET框架使得开发一个Web服务变得非常的容易和简单,但同样也导致容易出现一些错误。在进行系统构架时尽量避免这些常见的错误,能够保证你的企业和组织从Web服务的部署和应用上获得更多的收益。(end)
|
|
文章内容仅供参考
(投稿)
(8/15/2005) |
对 CIO信息化管理 有何见解?请到 CIO信息化管理论坛 畅所欲言吧!
|