首先介绍下Web Service是什么?
Web Service技术是一种基于标准的Web协议的可编程组件,我们可以把Web Service看做Web上的组件,Web服务提供者开放一系列的API,开发人员通过调用这些API来集成Web服务,构建自己的应用程序。
1.SOAP
SOAP(Simple Object Access Protocal)是在分散或在分布式环境中交换信息的简单协议,它基于XML协议,以XML形式提供了一个简单且轻量的用于在分散或分布环境下交换结构化和类型信息的机制,其本身并没有定义任何应用程序语义,如编程模型或特定语义的实现,而是通过提供一个有标准组件的包模型和在模块中编码数据的机制定义了一个简单的表示应用程序语义的机制,使其能够用于从信息传递到RPC的各种系统。SOAP规范定义了SOAP消息的格式,以及怎样通过HTTP协议来使用SOAP。SOAP最引人注目的特征是它可以在许多不同的软件和硬件平台上实现。这意味着 SOAP 可用于连接企业内部和外部的不同系统。过去曾试过多种方法以提出一个可用于系统集成的通用通信协议,但它们都没有像SOAP一样获得广泛的认可。为什么呢?因为与许多早期的协议相比,SOAP更小巧,而且更简单和易于实现。HTTP的普及和SOAP的简单性使你几乎可以在任何环境下调用它们,因此成为XML Web Service的理想基础。
2.WSDL
你会怎样向别人介绍你的Web Service有什么功能,以及每个函数调用时的参数呢?你可能会自己写一套文档,甚至口头告诉需要使用你的Web Service的人。这些非正式的方法至少都有一个严重的问题:当程序员坐到电脑前,想要使用你的Web Service的时候,他们的工具(如Visual Studio)无法给他们提供任何帮助,因为这些工具根本就不了解你的Web Service。解决方法是使用机器能阅读的方式提供一个正式的描述文档。Web Service描述语言(WSDL)就是这样一个基于XML的语言,用于描述Web Service及其函数、参数和返回值。因为是基于XML的,所以WSDL既是机器可阅读的,又是人可阅读的,这将是一个很大的好处。一些最新的开发工具既能根据你的Web Service生成WSDL文档,又能导入WSDL文档,生成调用相应Web Service的代码。
3.UDDI
UDDI(通用发现、说明和集成)是Web服务的黄页。是一套基于Web的、分布式地为Web Service 提供信息注册中心的实现标准,同时包含一组能使企业将自身提供的Web Service注册使得别的企业能够发现的访问协议。与传统黄页一样,你可以搜索提供所需服务的公司,阅读以了解所提供的服务,然后与某人联系以获得更多信息。
趣味理解
Web Service好比一个服务供应商,给其他厂家提供基础服务,其他厂家再将这个服务包装成自己的产品或者服务提供给别人或自己使用。有点像OEM了。既然两个公司需要合作,不可能靠一句话就可以的,就需要一些标准和规范的东西来实现。那么:
SOAP 就像两个公司之间签的合同,约束双方按一定规矩和标准办事。
WSDL 则像说明书,告诉别人你有什么,能给别人提供什么服务。
UDDI 好比你的公司需要在黄页或工商注册,企业的主营业务登记,方便别人查询。当然,你也可以不在 UDDI 中注册,就像在地下室开展业务,靠的是口头吆喝;但是如果你希望拓展市场,则需要 UDDI 以便能被客户发现,更方便地找到你。
Web Service是创建可互操作的分布式应用程序的新平台。Web Service 的主要目标是跨平台的可互操作性。为了达到这一目标,Web Service 是完全基于XML、XSD等独立于平台、独立于软件供应商的标准的。Web Service在应用程序跨平台和跨网络进行通信的时候是非常有用的。Web Service适用于应用程序集成、B2B集成、代码和数据重用,以及通过Web进行客户端和服务器的通信的场合。
当然,Web Service也不是万能的,你不能到处滥用Web Service。在有些情况下,Web Service 会降低应用程序的性能,而不会带来任何好处。例如,一台机器或一个局域网里面运行的同构应用程序就不应该用Web Service 进行通信。
到现在为止,我们已经讨论了如何与 Web Service 通信(SOAP),Web Service是怎样进行说明的(WSDL),以及如何查找 Web Service(UDDI)。这些内容构成了一套基本规范,为应用程序的集成和聚合提供了基础。根据这些基本规范,公司可以构建实际的解决方案,并从中获益。
1.接口是自说明的
接口的名字、参数和返回值应该一看就知道这接口大概是干什么用的。当然接口描述文档肯定是必需的,但这些描述文档的质量谁知道怎么样呢,谁有空天天翻着文档写东西呢,又有谁会背下来呢?所以让人眼前一亮的接口命名绝对值得,这也是所有代码书会告诉你应该遵守的一条规则。
2.服务接口粒度要合适
Web Service服务接口粒度太小了,那纯粹是不考虑XML解析性能了。一般新手容易犯这毛病,简单地把类的方法暴露出来做服务接口,这样其实是把原来在 local的调用放到了remote,除此之外几乎没有任何好处。粒度太大,会给使用者带来很多麻烦,因为在Web Service中,粒度很大的服务一般都需要很多参数来映射该服务各种各样的情况。
3.接口参数要尽量简单
只有一个参数的服务接口,往往不能满足业务需求。但过多的参数也提高了出错的几率,增加了测试的成本。所以,参数恰到好处为妙。
4.要提供对接口参数和返回值的校验
严格来说,对接口参数和返回值的验证也应该算是Web Service接口声明的一部分。增加对参数和返回值的校验,有利于减少调用者的疑惑,系统接受什么样的参数,返回值是什么格式都一目了然。但是这需要一个很好的权衡,否则调用者会觉得你暴露的方法很难用,因为限制太多了。比较理想的系统应该是宽进严出的,目标用户越多越应该注意这一点。要在宽进严出和全面校验之间做好平衡确实挺难的。简单的办法是,对要暴露的接口自己做测试,在测试的过程中体会这个度。一般来说如果自己感觉都不爽,那别人是绝对不会用的。
5.接口的返回值应该是简单的语言无关的
听见过很多人问如何返回DataSet之类的复杂类型,尤其是玩.NET的人,也许是VS.NET对封装DataSet提供了过于完美的支持吧。但对于XML来说,把任何复杂对象映射到XML文档都是困难的。就好比把三维向二维投影一样,复杂性增加了可不是一点半点。在XML中说到底所有的类型都是字符串,要想表达其他类型,就要添加额外的说明。可以看看rpc/encode方式WSDL文档的complexType部分,自行体会。
6.谨慎地抛出异常
对Web Service中的任何异常都应该进行相应的处理。可以简单地归纳为以下两种情况。
第1种情况是接口返回值是简单类型,比如bool型,就true和false两种情况,不抛出异常怎么办?选择有两种,一是抛出异常,二是改变接口,返回int用1和0对应true和false,用-1对应系统异常。
第2种情况是接口返回值是复杂对象,可以通过参数out string exceptionInfo来返回异常信息。
7.接口要尽量采用更新的标准
如何让一次定义的接口能服务得更好更久?从技术规范方面来说有两点:不超前,不落伍。超前,支持它的工具集不会太丰富,估计谁也不想弄出个看起来很美但是谁都用不了的东西;落伍,眼前所有的工具大概都支持,不过明天就不一定了,技术发展这么快,不能把自己累死吧。尽量采用更新的标准的意思是在不落伍的基础上要有前瞻性。举个简单的例子,今天再采用rpc/encode方式就显得不合时宜了,虽然它在前两年很流行,可今天都已经不提倡用了,明天说不定大家就都忘了。就算你及时更新了你的接口,客户也说不定已经换了供应商了。
8.要注意标准的通用性
虽然都是一样的标准,但标准有不同的版本,而且即使是同一个版本的标准,不同的工具实现起来也还是有细微差别的。如果用户是特定的还好说,采用些工具绑定的特性也没什么。但如果接口用户不是特定的人群,那就要注意了,在采用某一规范标准时不要用实现工具所特有的东西,否则很有可能造成客户的麻烦,导致只有很少一部分客户能使用你提供的接口。多一个客户就多一分钱啊,兄弟,干嘛跟钱过不去?
9.禁用HTTP POST/GET协议
除非另外指定,否则.NET将试图把Web服务绑定到3种协议:HTTP/POST、HTTP/GET和SOAP。之所以说"试图",是因为依赖于服务的参数和返回类型,HTTP/GET协议可能不可用。.NET生成的WSDL文件将自动包含绑定这3种协议的指令,客户程序可以自由选择使用哪种协议与服务通信。
只要在Web.config文件中加入下列内容,就可以删除对HTTP/POST和HTTP/GET协议的绑定:
- <webServices>
- <protocols>
- <remove name="HttpPost" />
- <remove name="HttpGet" />
- </protocols>
- </webServices>
为什么要避免通过HTTP/POST和HTTP/GET协议引出Web服务呢?主要的2个因素是安全性和互操作性。HTTP/GET的安全性不如SOAP,而且由于HTTP/GET常见于Web链接,怀有恶意的人可能利用它实施欺骗,使别人在不知不觉中用自己的安全标识调用Web服务,却还以为自己在单击Web链接。
就互操作性而言,SOAP是广泛应用的Web服务通信标准,而HTTP/GET和HTTP/POST不是。因此,对于.NET生成的WSDL文档中默认包含的HTTP/GET和HTTP/POST绑定,许多自动生成代理服务器的工具不会理解。因此,如果你的Web服务不是非绑定到HTTP/GET和HTTP/POST协议不可,最好取消这两种绑定。
10.用TcpTrace查看SOAP请求/应答消息
对于开发Web服务应用的人来说,调试可能是件异乎寻常的难事,因为无论是.NET SDK还是VS.NET,都没有提供工具来查看客户端和服务器之间的SOAP消息。
如果.NET和非.NET的客户端、服务器端的交互过程出现了问题,要想找出问题的根源,拥有查看SOAP消息的能力就尤为重要,因为这类问题往往与SOAP消息的格式有关(例如"消息中包含了SOAPAction吗?")。
tcpTrace(www.pocketsoap.com/tcptrace)是一个查看这类消息交换过程的优秀工具,它通过设置一个客户端和服务器端之间的隧道工作。启动tcpTrace时,它会要求输入目标URL和端口号,以及tcpTrace监听的本地端口号。这样,你就可以通过设置代理stub的URL属性,把stub指向这个本地端口(例如localhost:8080)。tcpTrace能够记录所有的请求和应答HTTP消息。
tcpTrace的一个局限是,它在消息流程中所处的位置决定了它不能用来查看通过SSL发送的消息。如果你要查看通过SSL发送的SOAP消息,只能编写一个定制的ISAPI过滤器。
11.简化接口设计
在众多有关N-层应用设计的论述中,简化接口设计这一设计要诀可以说是随处可见。但是,对于Web服务这样的分布式计算环境来说,简化接口设计的重要性更加突出。
在设计分布式应用时,出于性能和可伸缩性的考虑,应当保证客户端和服务器端之间的调用尽可能地少。减少网络调用不仅有利于减少通信开销(如果只用1个SOAP消息可以达到目标,就绝对不要发3个消息),降低网络流量,而且提高了应用的性能。显然,这一切都是开发者梦寐以求的目标。那么简化的接口到底有何特征呢?
首先来看一个复杂接口的例子:
- namespace ChattyService
- {
- public class ChattyService : WebService
- {
- private string username;
- private string password;
- public string Username
- {
- [WebMethod]
- set
- {
- username = Username;
- }
- }
- public string Password
- {
- [WebMethod]
- set
- {
- password = Password;
- }
- }
- [WebMethod]
- public bool Logon()
- {
- //验证身份
- return true;
- }
- }
- }
在这个例子中,username和password是两个属性,调用logon()方法之前首先必须设置这两个属性。有一个问题光看这段代码不太容易注意到,这就是username和password都作为Web方法引出。这就是说,每次对属性的get/set操作都会导致一个对服务的调用。
按照简化接口设计的要求,改进后的代码如下:
- namespace ChattyService
- {
- public class ChattyService : WebService
- {
- [WebMethod]
- public bool Logon(string Username, string Password)
- {
- //验证身份
- return true;
- }
- }
- }
现在,username和password成了logon()方法的参数。修改之后的代码的优点在于,它把登录操作对服务器的3次调用降低到了1次。另一方面,如果参数的个数太多,这个方法可能看起来很不像样。这时,可能要把方法的参数整理成几个复杂类型,例如,把username和password 两个参数封装到一个credential(证书)对象中。
12.避免使用ASP.NET会话状态
.NET实现的会话状态管理功能解决了它的前辈ASP 3.0存在的许多问题,例如请求串行化等,但仍存在一些局限。应当认识到,.NET的会话状态管理功能不是专门为Web服务环境中的会话状态而设计的,而是为了在范围更广泛的ASP.NET应用中管理会话状态而设计的,它依赖于HTTP Cookie(有一种通过改写URL实现的不需要Cookie的模式,但不适用于Web服务)。
Cookie是HTTP独有的。在Web上,所有的浏览器都支持HTTP,所以Cookie非常适合在Web应用中使用。但是,在Web服务中应用Cookie却把服务限定到了HTTP协议上。另一方面,SOAP协议的运行是独立于传输协议的,因此如果把Web服务应用限制到HTTP协议上,那么应用的灵活性也将受到限制,一旦要通过非HTTP的传输协议(例如SMTP)提供服务,事情就会变得很麻烦。