ajax访问Web服务(Yahoo搜索的例子)[转]

多 年以来一直存在一个软件工程问题:从一台机器调用另一台机器上的服务或方法,即使这些机器使用完全不同的硬件或软件。对于这个问题,最近提出的解决方案是 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 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]);
    }
 
    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" οnclick="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?"
                     + "appid=your_app_id" + "&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);
    }
}
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请求。
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值