Ajax - 访问Web服务

4.8  访问Web服务
多年以来一直存在一个软件工程问题:从一台机器调用另一台机器上的服务或方法,即使这些机器使用完全不同的硬件或软件。对于这个问题,最近提出的解决方案是Web服务。几年前,Web服务大受吹捧,它的头上围绕着耀眼的光环,有些人认为Web服务就是分布式软件开发的“圣杯”。后来,它的光芒逐渐黯淡下来,Web服务最终找到了自己合适的位置,它是支持异构计算机系统相互操作的一种有用的工具。
Web服务通常用作为计算机系统之间的通信管道,这与CORBA(公共对象请求代理体系结构)、RMI(远程方法调用)或DCOM(分布式组件对象模型)很相似。区别在于,Web服务独立于具体的开发商,可以采用大量编程工具和平台来实现。为了支持更高层次的互操作性,Web服务是基于文本的协议,通常在HTTP之上实现。由于Web服务是基于文本的协议,所以几乎总能使用某种XML。
最著名的 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文档。这个模式听上去是不是很熟悉?你说对了,它与本书中你见过的Ajax例子是一样的。
XMLHttpRequest 对象非常适合作为基于 REST Web 服务的客户。使用 XMLHttpRequest对象,可以向Web服务异步地发出请求,并解析得到的XML响应。对于Yahoo! Web服务,XMLHttpRequest对象可以向Yahoo!发出请求,搜索指定的项。一旦Yahoo!返回响应,则使用JavaScript DOM方法解析响应,并向页面动态地提供结果数据。
代码清单4-15展示了如何使用Ajax技术访问Yahoo! Web服务,并向页面提供结果。页面上的文本字段允许用户指定搜索项。用户可以使用选择框来指定需要显示多少个结果。点击Submit(提交)按钮就能启动搜索。
不过,先等等!第2章我们曾经说过,XMLHttpRequest对象只能访问发起文档(即调用脚本)所在域中的资源。如果试图访问其他域的资源,可能因为浏览器的安全限制而失败。怎么解决呢?
解决办法有好几个。在第2章已经了解到,浏览器实现安全沙箱的方式各有不同。IE会询问用户是否允许访问另一个域中的资源。Firefox则会报告错误,自动失败,虽然可以用专用于Firefox的JavaScript代码避免这种行为。
还有一个选择,这也是本例中要采用的方法,就是建立Yahoo!的网关,它与XMLHttp-
Request脚本在同一个域中。由网关接收来自XMLHttpRequest对象的请求,并把它转发到Yahoo! Web服务。Yahoo!做出响应返回结果时,网关再把结果路由传送到浏览器。通过使用这种方法,就能避免使用浏览器特定的JavaScript。另外,这种方法也更加健壮,因为你还可以扩展网关,让它支持其他的Web服务提供者。
代码清单 4-15   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 searchString = document.getElementById("searchString").value;
   if(searchString == ""){
         return;
   }
    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;
    //query,results都是固定的,并且有一定的要求,还有其他参数的,具体看我最后给的链接
    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");
        }
    }
    //可以添加 加载结果完成 前的等待页面
    //else{
        // 等待页面的DIV,完成后把这个DIV清除
    //}
}
 
function parseSearchResults() {
    var resultsDiv = document.getElementById("results");
    while(resultsDiv.childNodes.length > 0) {
        resultsDiv.removeChild(resultsDiv.childNodes[0]);
    }
 
    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);                              //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="15">15</option>
        <option value="20">20</option>
        <!-- 显示的记录数默认是10 ,最大是20而已-->
    </select>
    <br/><br/>
    <input type="button" value="Submit" onclick="doSearch();"/>
  </form>
 
  <h2>Results:</h2>
  <div id="results"/>
 
</body>
</html>
点击页面上的Submit(提交)按钮将调用 doSearch函数。 这个函数使用 createQuery- String函数来创建目标URL, createQueryString函数负责把搜索项和显示的最大结果数(即最多显示多少个结果)放在查询串中。需要注意,参数名( queryresults)都是Yahoo! Search API定义的。
createQueryString函数创建的查询串发送给Yahoo! Search网关。在这个例子中,网关实现为名为 YahooSearchGatewayServlet的Java servlet(见代码清单4-16)。这个servlet的目的很简单,就是转发对Yahoo! Search URL的所有请求,并把结果传给浏览器。当然,这个网关也可以用其他语言(而不是Java)来实现。这个网关很简单,在XMLHttpRequest对象需要访问其他域中的资源时,这个网关确实能解决问题。
代码清单 4-16   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? "         
        " http://local.yahooapis.com/LocalSearchService/V3/localSearch ?"        //上面的已经不能用了,这是新的
                     + "appid=your_app_id " // + "&type=all";    appid是必需的,type没有了
                     + "&zip=94306";              //没这个查询没结果,我都不是很清楚, 邮政编码
 
    protected void processRequest(HttpServletRequest request
                                               , HttpServletResponse response)
    throws ServletException, IOException {
 
        String url = YAHOO_SEARCH_URL + "&" + request.getQueryString ();//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);
    }
}
Yahoo! Search把结果返回给网关,而且网关将结果再转发给浏览器后,会调用 parse-
SearchResults
函数。这个函数从XMLHttpRequest对象获取得到的XML文档,并查找所有标记名为 Result的元素。
Result元素传给 parseResult函数。这个函数使用Result元素的子元素 TitleSummaryClickUrlUrl创建内容,并增加到页面。
可以看到,与基于REST的Web服务结合使用时,Ajax技术相当强大。如果想在你自己的域中访问Web服务,用JavaScript就可以完成。否则,当访问其他域的资源时,就要创建外部资源的某种网关,这样就能避免浏览器安全沙箱问题。
图4-15显示了结合使用Yahoo! Search Web服务和Ajax的搜索结果。
图4-15  结合使用Yahoo! Search Web服务和Ajax的搜索结果
Ajax也能与SOAP一同使用吗?
可以结合使用Ajax和SOAP吗?答案很简单——可以。 Ajax 技术和基于 SOAP Web 服务可以一同使用,不过,与使用基于 REST Web 服务相比,这需要做更多的工作。
REST和SOAP都把响应返回为XML文档。二者之间最显著的差异是,REST将请求作为带查询串参数的简单URL发送,而SOAP请求是具体的XML文档,通常通过 POST而不是 GET发送。
结合使用SOAP和Ajax时,要求以某种方式创建SOAP请求的XML,这可能并不容易。一种做法是使用串连接来创建请求XML。尽管概念上讲很简单,但这种方法有些混乱,而且很容易出错,如很容易这儿忘了双引号,那儿忘了加号。
还有一种选择是使用一个XMLHttpRequest请求从网站加载静态XML文档,文档是SOAP请求的模板。一旦加载了模板,就可以使用JavaScript DOM方法来修改模板,使之满足特定的请求。请求准备好后,再用第二个XMLHttpRequest请求发送新创建的SOAP请求。

responseXML:

 

<? xml version="1.0"  ?>  
< ResultSet  xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"  xmlns ="urn:yahoo:lcl"  xsi:schemaLocation ="urn:yahoo:lcl http://api.local.yahoo.com/LocalSearchService/V3/LocalSearchResponse.xsd"  totalResultsAvailable ="19"  totalResultsReturned ="1"  firstResultPosition ="1" >
  
< ResultSetMapUrl > http://maps.yahoo.com/broadband/?q1=Palo+Alto%2C+CA+94306 &tt =ajax &tp =1 </ ResultSetMapUrl >  
< Result  id ="32213349" >
  
< Title > Ajax Custom Plastics </ Title >  
  
< Address > 34585 7th St </ Address >  
  
< City > Union City </ City >  
  
< State > CA </ State >  
  
< Phone > (510) 476-8000 </ Phone >  
  
< Latitude > 37.591159 </ Latitude >  
  
< Longitude > -122.007798 </ Longitude >  
< Rating >
  
< AverageRating > NaN </ AverageRating >  
  
< TotalRatings > 0 </ TotalRatings >  
  
< TotalReviews > 0 </ TotalReviews >  
  
< LastReviewDate  />  
  
< LastReviewIntro  />  
  
</ Rating >
  
< Distance > 12.31 </ Distance >  
  
< Url > http://local.yahoo.com/details?id=32213349 &stx =ajax &csz =Union+City+CA &ed =A_zEvq160Sy3zcQJxpKUsvvQnvLHOILp6hc8bPPfRwDnzV3Br.iK1ClzZB_v.Jo3ASrvVg-- </ Url >  
  
< ClickUrl > http://local.yahoo.com/details?id=32213349 &stx =ajax &csz =Union+City+CA &ed =A_zEvq160Sy3zcQJxpKUsvvQnvLHOILp6hc8bPPfRwDnzV3Br.iK1ClzZB_v.Jo3ASrvVg-- </ ClickUrl >  
  
< MapUrl > http://maps.yahoo.com/maps_result?name=Ajax+Custom+Plastics &desc =5104768000 &csz =Union+City+CA &qty =9 &cs =9 &ed =A_zEvq160Sy3zcQJxpKUsvvQnvLHOILp6hc8bPPfRwDnzV3Br.iK1ClzZB_v.Jo3ASrvVg-- &gid1 =32213349 </ MapUrl >  
  
< BusinessUrl > http://www.ajaxmfg.com/ </ BusinessUrl >  
  
< BusinessClickUrl > http://www.ajaxmfg.com/ </ BusinessClickUrl >  
< Categories >
  
< Category  id ="96931027" > Plastic Products </ Category >  
  
</ Categories >
  
</ Result >
  
</ ResultSet >
<!--   ws05.search.scd.yahoo.com compressed/chunked Fri Aug 24 09:08:31 PDT 2007 
  
-->  

 点击看看:http://local.yahooapis.com/LocalSearchService/V3/localSearch?appid=my_test_id&query=ajax&results=1&zip=94306

Yahoo! Search Web Services官方说明文档:http://developer.yahoo.com/search/local/V3/localSearch.html

红色部分为lin49940修改

原书链接:http://book.csdn.net/bookfiles/11/100117041.shtml

你可能感兴趣的:(Ajax,Yahoo,search,XMLhttpREquest,SOAP,web服务)