内容


使用 Ajax 和 Web 服务

结合使用这两项先进技术比您想象的简单

Comments

什么是 Web 服务?

Web 服务是使用万维网公开应用程序功能的方法。它通过使用开放协议来公开应用程序功能,因此任何使用服务的应用程序,只要能访问 Web,都可访问 Web 服务。

典型的 Web 服务交互包括使用者(使用 Web 服务的远程应用程序)向服务发送 XML 消息。然后服务解析消息,回送响应,同样以 XML 格式。然后使用者以同样方式解析响应,将从服务接收到的信息投入使用。

大多数情况下,Web 服务中使用的 XML 语言是 SOAP。SOAP 原先是 Simple Object Access Protocol 的缩写,但由于某些原因已不是这样。协议包含三个部分:信封、数据类型规则,以及定义操作请求和响应的方法。

Web 服务在另一个 XML 文档中有定义,这个 XML 文档称为 Web Services Description Language (WSDL)。WSDL 指定了使用 Web 服务公开的操作、操作使用的数据类型定义、用于和 Web 服务通信的协议,以及 Web 服务本身的位置。

Web 服务的优势是允许用不同语言编写、在不同平台上开发的应用程序可以在广阔的 Internet 上相互通信。

什么是 Ajax?

Ajax 是 Web 开发人员用来实现富客户端表现的最先进的技术。它通过在不影响当前视图的情况下调用新请求来完成。然后返回一个 XML 文档显示给用户,通常作为当前视图的子页。简而言之,Ajax 提供服务端动态内容,同时看上去像客户端动态内容。

Ajax 实现其功能主要通过使用 XMLHttpRequest DOM API,Web 开发人员直到 Ajax 出现才开始使用。请求本身可以是 GETPOST

对于任何一个请求,都会返回响应,返回的响应也可能是错误。如果响应没有错误,就会用响应的实际文本更新当前视图。

记住伏尔泰的一句名言(即,“神圣罗马帝国既非神圣,亦非罗马,更非帝国”),深入研究各种 Ajax 实现会发现,Ajax 不需要 JavaScript 代码,不需要 XML,也不需要异步。除去那些,剩下的只有连接词(and)。但缩写词听上去很棒,因此业界决定保留它。

Ajax 与 Web 服务如何结合在一起

想一想:富客户端体验,加上 Internet 上到处可访问的服务。是的,真棒。

Ajax,如您所见,在幕后执行请求,并向 Web 页面显示出响应(或其中一部分),而不会更新整个网页。请求可以是简单的 HTTP 请求,发送给公开的 Web 服务的也可以是 SOAP 消息。然后 Ajax 例程中的 JavaScript 端解析响应(也是 SOAP 格式)并提取所需数据返回给应用程序,展示给用户。

确实很简单。

fishinhole.com 的业务需求

fishinhole.com 的董事会希望其他 Web 应用程序可更容易地访问公司库存。他们想,如果其他网站,包括游钓论坛、博客,甚至是竞争对手零售商,都能轻松访问 fishinhole.com 的库存列表,销售将增加 23.7%。

您可能不关心 23.7% 这个数字式怎么来的,而是关注如何向其他 Web 应用程序公开库存。很快就可得出结论:要创建 Web 服务。Web 服务可以让使用者根据鱼饵类型提交请求,查询库存。目前的鱼饵类型有 CastingTrollingOther。Web 服务根据使用者提供的鱼饵类型返回鱼饵清单。

还该意识到,您的公司已超出 Other 类型鱼饵。应该在 Web 服务中妥善处理。

部署简单的 Web 服务

使用 PHP 创建简单的 Web 服务。PHP 以及 NuSOAP,是我见过的快速创建 Web 服务最简单的方法。

首先,确认取得 NuSOAP(查看 参考资料),将所有的 PHP 文件放在部署 PHP Web 服务的文件夹下。

安装完 NuSOAP 后,就可以开始编写实际 Web 服务。清单 1 包含所有内容。

清单 1. webservice.php
<?php
require_once('nusoap.php');
$server = new soap_server;
$server->register('hello');
$server->register('retrieveByType');
function hello($name) {
    return 'Hello, ' . $name;
}

function retrieveByType($type) {
	if ($type == 'trolling') {
		$arr[0] = 'Donzai Deep Swimmer 5 1/4 inch';
		$arr[1] = 'Yosubi Squid-like 4 inch';
		$arr[2] = 'Fortunata Imperial High Action';
	} else if ($type == 'casting') {
		$arr[0] = 'Silver Spring Mirrors Size 00';
		$arr[1] = 'Gold Spring Mirrors Size 0';
		$arr[2] = 'Mini Minnow Blue';
	} else {
		$arr[0] = 'None found!';
	}

	return $arr;
}

$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
$server->service($HTTP_RAW_POST_DATA);
?>

首先,注意 require_once('nusoap.php') 行。这一行允许 PHP Web 页面使用 nusoap.php 中定义的类。您也许想知道为何需要 NuSOAP 相关的其他 PHP 文件。实际情况是,nusoap.php 依赖于这些文件,就像页面依赖 nusoap.php。

下一行实例化 soap_server 对象。不出所料,这将创建使用 SOAP 协议的 Web 服务。

下一行注册 retrieveByType 函数以将其公开为 Web 服务操作。如果再往下看,会发现有个已定义函数,名为 retrieveByType。那么为什么需要这一步? 因为如果不注册该函数,它只是可供包含它的本 PHP 页面或其他 PHP 页面调用的简单 PHP 函数。因此本行是通知 soap_server 对象将该函数公开为 Web 服务用户可用的操作。

下一段代码实际是实现 retrieveByType 方法。这是个简单的 PHP 函数,接收一个参数:type,它可以是 trollingcastingother。如您所知,这些是 fishinhole.com 用户选的三个鱼饵类型。

retrieveByType 方法返回数组。数据包含请求类型特定的鱼饵列表。现在对 trolling 有三种不同鱼饵类型,casting 有三种不同鱼饵类型。注意还有一种 “全部包含”,其中有 Other 和未识别类型。对于这些 Web 服务只简单返回 None Found! 作为数组惟一元素。

最后两行在 Web 服务被访问时执行。第一行检查是否有 POST 数据。如果没有,POST 数据设为空字符串。第二行用来自 POST 的数据执行 Web 服务。POST 数据包含 SOAP 消息。当查看使用者的时候将会看到更多。

将该页面保存为 webservice.php 并放到安装 NuSOAP 的文件夹下。显然,需要将该页面放到能处理 PHP 文件的地方。目前大多数托管解决方案支持 PHP,所以即使没有现成的 PHP 处理器,也不会有问题。

现在通过访问以下 URL 快速测试 Web 服务:http://yourhost/yourdirectory/webservice.php。显然,需要将 yourhostyourdirectory 分别用实际存放文件的主机和文件夹替换。

得到的响应应该是 SOAP 响应(查看清单 2)。如果不是,则 Web 服务运行不正常。

清单 2. SOAP 响应
<?xml version="1.0" encoding="ISO-8859-1" ?> 
<SOAP-ENV:Envelope 
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"> 
<SOAP-ENV:Body> 
<SOAP-ENV:Fault> 
<faultcode xsi:type="xsd:string">SOAP-ENV:Client</faultcode> 
<faultactor xsi:type="xsd:string" /> 
<faultstring xsi:type="xsd:string">method '' not defined in service</faultstring> 
<detail xsi:type="xsd:string" /> 
</SOAP-ENV:Fault> 
</SOAP-ENV:Body> 
</SOAP-ENV:Envelope>

编写访问 Web 服务的页面

从编写实际访问 Web 服务的 JavaScript 代码开始,如清单 3 所示。

清单 3. invokeService() JavaScript 函数
function invokeService(type) {
 soapMessage = '<?xml version="1.0" encoding="ISO-8859-1"?>';
 soapMessage+='<SOAP-ENV:Envelope SOAP-ENV:encodingStyle=""';
 soapMessage+=' xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"';
 soapMessage+=' xmlns:xsd="http://www.w3.org/2001/XMLSchema"';
 soapMessage+=' xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">';
 soapMessage+=' <SOAP-ENV:Body> <ns1:retrieveByType xmlns:ns1="http://fishinhole.com">';
 soapMessage+=' <type xsi:type="xsd:string">' + type + '</type>';
 soapMessage+=' </ns1:retrieveByType> </SOAP-ENV:Body> </SOAP-ENV:Envelope>';
 
 if(window.XMLHttpRequest) {
  httpRequest=new XMLHttpRequest();
 } else if (window.ActiveXObject) { 
  httpRequest=new ActiveXObject("Microsoft.XMLHTTP"); 
 }
                  
 httpRequest.open("POST",url,true);
 if (httpRequest.overrideMimeType) { 
  httpRequest.overrideMimeType("text/xml"); 
 }
 httpRequest.onreadystatechange=populateDiv;
      
 httpRequest.setRequestHeader("Man", url + " HTTP/1.1")
 httpRequest.setRequestHeader("MessageType", "CALL");
 httpRequest.setRequestHeader("Content-Type", "text/xml");

 httpRequest.send(soapMessage);
 valTimeout=setTimeout("timeout(httpRequest);",120000);
}

函数名为 invokeService,接收一个参数:type。不用说,这对应于 Web 服务操作(retrieveByType)接收的 type 参数。换句话说,type 参数是包含 castingtrollingother 的字符串。

函数的前几行组装 SOAP 消息。对于 SOAP 的详细描述已远远超出本文范围。尽管如此,XML 的某些部分却比较直观。请注意 XML 其中一个元素直接对应操作名(retrieveByType)。该元素的子元素根据 webservice.php 文件中指定的参数名(type)来命名。并且那个元素值是传入该 JavaScript 函数的字符串参数,也叫做 type

下面几行创建跨浏览器兼容请求对象。这是用来访问 Web 服务的对象。

请求对象创建后,函数设置回调函数,本例中是 populateDiv() 函数。这是在网页上显示库存列表的函数。

函数然后设置头部。 值得引起注意的是,您正创建与 SOAP 兼容的内容类型:text/xml。还有,请注意 url 变量的使用。当创建自己的 Web 页面后,需要将变量指向自己 Web 服务的 URL。看上去就像这样:http://www.myhost/myservicedir/webservice.php。

最后,使用请求对象发送 SOAP 消息,在服务不响应时设置超时。

下一步,看看响应 Ajax 调用和显示库存的 JavaScript 代码,如清单 4 所示。

清单 4. populateDiv() JavaScript 函数
function populateDiv(){
 try {
      if(httpRequest.readyState==4) {
         if(httpRequest.status==200) {
            clearTimeout(valTimeout);
     	    var text = httpRequest.responseText;
	    if (window.DOMParser) {
		parser=new DOMParser();
		xmlDoc=parser.parseFromString(text,"text/xml");
	    } else {
	        xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
		xmlDoc.async="false";
		xmlDoc.loadXML(text); 
	    } 
	
            var html = "";
	    for (i=0;i<xmlDoc.getElementsByTagName("item").length;i++) {
	     html += "<br/>" + 
             xmlDoc.getElementsByTagName("item")[i].childNodes[0].nodeValue;
	    }

	    var resultDiv=document.getElementById("resultDiv");
	    resultDiv.innerHTML = html;         		
         }
      } 
 } catch(e) { 
     alert("Error!"+e.description); 
 }      
}

使用过 Ajax 的人对前面几行都应该很熟悉。回想一下,每次请求对象经历状态改变的时候都会调用这个函数。这里特别要注意的是当请求对象返回有效响应时(200 代码)。

当返回有效响应,清空超时并获取响应文本。记住,响应文本其实是 SOAP 响应,因此是 XML 格式。这意味着需要使用 JavaScript 编程语言来将 XML 解析成重要信息。

再看下面几行。这几行实例化跨浏览器兼容的 XML 文档对象,它可由 JavaScript 编程语言解析。由于 SOAP 响应是 XML 文档,因此可像其他 XML 文档一样解析。

下一步创建一些 HTML。以空 HTML 字符串开始。然后,将 SOAP 消息解析成 item 元素。请记住,Web 服务返回一个数组。有可能 item 元素不止一个。for 循环实际是说 “对每个 item 元素,做以下事情。”

“以下事情” 是指:JavaScript 代码获取 item 元素的第一个子元素。这个例子中,只有一个子元素,是个简单字符串。然后它提取该子元素的值,即库存中的一项。出于美观的目的,我在库存项前加上 <br/> 标记。这样列表每项都在单独行中显示。最后,所有行连接成现在的 HTML,当 for 循环完成后,就有了完整列表。

当 HTML 完成后,就可以将其放到页面上。本例中,名为 resultDivdiv 元素内容将用刚创建的 HTML 重写。结果是,当用户在页面上从下拉框选择新类型时,库存项清单就会出现。

说道 HTML,看看实际 Web 页面所需的 HTML,如清单 5 所示。

清单 5. 客户端的 HTML
<body>    
   <div style="position:relative;left:0px;background-color:blue;margin:0px;">   
   <h2 align="center"><font color="#ffffff">FishinHole.com Web Service</font></h2></div>
   <table align="center" cellpadding="6px" cellspacing="6px" width="400" border="0">
      <tr>
         <td width="80" valign="center"><font color="black">
          Lure Type:</font></td>
         <td>
	  <select name="lureType" id="lureType" onchange="changeTypes()">
	   <option value="">-SELECT-</option>
	   <option value="trolling">Trolling</option>
	   <option value="casting">Casting</option>
	   <option value="other">Other</option>
	  </select>
         </td>
	 <td width="150"> </td>
         <tr>
          <td colspan="3">
            <div id="resultDiv"></div>
          </td>
       </tr> 
    </table>    
</body>

这里没什么特别复杂的。下拉框有三种鱼饵类型:trolling、casting 和 other。我使用了 onchange 属性,这样当用户选择新的鱼饵类型时,调用 Ajax 请求的 JavaScript 代码会自动执行。

还要注意,resultDiv div 元素出现了。这是库存清单显示的地方。

测试

将刚创建的 HTML 页面放在可解释 HTML 和 JavaScript 代码的平台上。如果有 Microsoft® Windows® 操作系统,将这个页面放到硬盘上。

接下来,就是访问 Web 页面。会在屏幕中间看到下拉框。现在,所选条目应该是 -SELECT-。将其改成 Trolling。等待几秒钟,您会看到三项的库存列表显示在屏幕上。祝贺您,测试成功!

如果遇到问题,确认 url 变量设置是否对应。还有,JavaScript 代码可能会报告异常,并弹出窗口,其中是描述。这会提示错误的线索。

结束语

Web 服务是向可访问 Internet 的用户公开操作的功能强大的方法。Ajax 是向 Web 应用程序用户提供丰富体验的方法,它可改变显示内容而不刷新页面。您可以同时使用二者来创建功能强大的 Web 应用程序,它可以模拟分布式对象应用程序,并呈现出专业的界面。


下载资源


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Web development, SOA and web services
ArticleID=604196
ArticleTitle=使用 Ajax 和 Web 服务
publish-date=12202010