最其名的WEB服务实现是SOAP(简单对象访问协议)。SOAP是由W3C管理的规约,它是XML协议,对于如何调用远程过程给出了定义。
WSDL(Web服务描述语言)文档也是XML文档,描述了如何创建Web服务的客户。通过提供WSDL文档,Web服务提供者就能很轻松地为可能的客户创建客户端代码。WSDL和SOAP通过一同使用,不过不一定非得这亲,因为这两个规约是分维护的。
尽管人们在简化SOAP实现上做出了很大努力,但SOAP还是一个很难使用的技术,只有在跨平台互操作性确实是一个很重要的需求时才会作用SOAP。实现Web服务还有一种更简单的方法,称为REST(代表传输),它在开发人员中享有越来越高的知名度,这些开发人员一方面希望得到SOAP好处的80%,另一方面只希望付出SOAP代码的20%。
Yahoo!选择REST作为其公共Web服务的协议,Yahoo!认为基于REST的服务很容易理解,而且很推崇REST的“平易近人”,因为当前大多数编程语言都可以访问REST。实际上,Yahoo!相信,与SOAP相比,REST的门槛更低,使用也更容易。
通过使用REST,建立请求时可以先指定一个服务入口URL,再向查询串追加搜索参数。服务将结果返回为XML文档。
XMLHttpRequest对象非常适合作为基于REST的Web服务的客户。使用XMLHttpRequest对象,可以向Web服务异步地发出请求,并解析得到XML响应。对于Yahoo!返回响应,则使用JavaScriptDOM方法解析响应,并向页面动态地提供结果数据。
示例展示了如何使用Ajax技术访问Yahoo!Web服务,并向页面提供结果。页面上的文本字段允许用户指定搜索项。用户可以使用选择框来指定需要显示多少个结果。点击Submit按键就能启动搜索。
但是XMLHttpRequest对象只能访问发起文档所在域的资源。这里的解决办法,就是建立Yah!的网关,它与XMLHttpRequest脚本在同一个域中,由网关接收来自XMLHttpReqest对象的请求,并把它转发到Yahoo!Web服务。Yahoo!做出响应返回结果,网关再把结果路由传送到浏览器。通过使用这种方法,就能避免使用浏览器特定的JavaScript。
以下是搜索1条“ajax”时Yahoo!返回的XML:
<?xml version="1.0" encoding="UTF-8"?> <ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:yahoo:srch" xsi:schemaLocation="urn:yahoo:srch http://api.search.yahoo.com/WebSearchService/V1/WebSearchResponse.xsd" type="web" totalResultsAvailable="257000000" totalResultsReturned="1" firstResultPosition="1" moreSearch="/WebSearchService/V1/webSearch?query=ajax&appid=thunderboltsoftware&region=us"> <Result> <Title>AJAX - Wikipedia</Title> <Summary>Background about the web development technique for creating interactive web applications.</Summary> <Url>http://en.wikipedia.org/wiki/AJAX</Url> <ClickUrl>http://en.wikipedia.org/wiki/AJAX</ClickUrl> <DisplayUrl>en.wikipedia.org/wiki/AJAX</DisplayUrl> <ModificationDate>1255590000</ModificationDate> <MimeType>text/html</MimeType> <Cache> <Url>http://uk.wrs.yahoo.com/_ylt=A0PDB2P12tpKixsAiH7dmMwF;_ylu=X3oDMTBwOHA5a2tvBGNvbG8DdwRwb3MDMQRzZWMDc3IEdnRpZAM-/SIG=16lq3593n/EXP=1255943285/**http%3A//66.218.69.11/search/cache%3Fei=UTF-8%26appid=thunderboltsoftware%26type=all%26query=ajax%26results=1%26ts=1255856883765%26u=en.wikipedia.org/wiki/AJAX%26d=TGfjPd29Tpo6%26icp=1%26.intl=us</Url> <Size>70721</Size> </Cache> </Result> </ResultSet><!-- ws03.ydn.gq1.yahoo.com uncompressed/chunked Sun Oct 18 02:08:05 PDT 2009 -->
yahooSearch.html清单:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Yahoo! Search Web Services</title> <script type="text/javascript"> var xmlHttp; function createXMLHttpRequest() { if (window.ActiveXObject) { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } else if (window.XMLHttpRequest) { xmlHttp = new XMLHttpRequest(); } } //程序入口 function doSearch() { var url = "YahooSearchGateway?" + createQueryString() + "&ts=" + new Date().getTime(); createXMLHttpRequest(); xmlHttp.onreadystatechange = handleStateChange; xmlHttp.open("GET", url, true); xmlHttp.send(null); } function createQueryString() { var searchString = document.getElementById("searchString").value; searchString = escape(searchString); var maxResultsCount = document.getElementById("maxResultCount").value; var queryString = "query=" + searchString + "&results=" + maxResultsCount; return queryString; } function handleStateChange() { if(xmlHttp.readyState == 4) { if(xmlHttp.status == 200) { parseSearchResults(); } else { alert("Error accessing Yahoo! search"); } } } //回调函数 function parseSearchResults() { var resultsDiv = document.getElementById("results"); while(resultsDiv.childNodes.length > 0) { resultsDiv.removeChild(resultsDiv.childNodes[0]); } document.write(xmlHttp.responseText); var allResults = xmlHttp.responseXML.getElementsByTagName("Result"); var result = null; for(var i = 0; i < allResults.length; i++) { result = allResults[i]; parseResult(result); } } function parseResult(result) { var resultDiv = document.createElement("div"); var title = document.createElement("h3"); title.appendChild(document.createTextNode(getChildElementText(result, "Title"))); resultDiv.appendChild(title); var summary = document.createTextNode(getChildElementText(result, "Summary")); resultDiv.appendChild(summary); resultDiv.appendChild(document.createElement("br")); var clickHere = document.createElement("a"); clickHere.setAttribute("href", getChildElementText(result, "ClickUrl")); clickHere.appendChild(document.createTextNode(getChildElementText(result, "Url"))); resultDiv.appendChild(clickHere); document.getElementById("results").appendChild(resultDiv); } function getChildElementText(parentNode, childTagName) { var childTag = parentNode.getElementsByTagName(childTagName); return childTag[0].firstChild.nodeValue; } </script> </head> <body> <h1>Web Search Using Yahoo! Search Web Services</h1> <form action="#"> Search String: <input type="text" id="searchString"/> <br/><br/> Max Number of Results: <select id="maxResultCount"> <option value="1">1</option> <option value="10">10</option> <option value="25">25</option> <option value="50">50</option> </select> <br/><br/> <input type="button" value="Submit" onclick="doSearch();"/> </form> <h2>Results:</h2> <div id="results"/> </body> </html>
YahooSearchGatewayServlet.java清单:
package ajaxbook.chap4; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import javax.servlet.*; import javax.servlet.http.*; public class YahooSearchGatewayServlet extends HttpServlet { private static final String YAHOO_SEARCH_URL = "http://api.search.yahoo.com/WebSearchService/V1/webSearch?appid=thunderboltsoftware" + "&type=all"; protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String url = YAHOO_SEARCH_URL + "&" + request.getQueryString(); HttpURLConnection con = (HttpURLConnection)new URL(url).openConnection(); con.setDoInput(true); con.setDoOutput(true); con.setRequestMethod("GET"); //Send back the response to the browser response.setStatus(con.getResponseCode()); response.setContentType("text/xml"); BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream())); String input = null; OutputStream responseOutput = response.getOutputStream(); while((input = reader.readLine()) != null) { responseOutput.write(input.getBytes()); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } }
基于REST的Web服务结合使用时,Ajax技术相当强大。如果想在你自己的域中访问Web服务,用JavaScript就可以完成。否则,当访问其他域的资源时,就要创建外部资源的某种网关,这样就能避免浏览器安全沙箱问题。
运行结果: