WIKI使用導(dǎo)航
站長百科導(dǎo)航
站長專題
- 網(wǎng)站推廣
- 網(wǎng)站程序
- 網(wǎng)站賺錢
- 虛擬主機(jī)
- cPanel
- 網(wǎng)址導(dǎo)航專題
- 云計(jì)算
- 微博營銷
- 虛擬主機(jī)管理系統(tǒng)
- 開放平臺(tái)
- WIKI程序與應(yīng)用
- 美國十大主機(jī)
Ajax- 訪問Web服務(wù)
導(dǎo)航: 上一頁 | ASP | PHP | JSP | HTML | CSS | XHTML | aJAX | Ruby | JAVA | XML | Python | ColdFusion
多年以來一直存在一個(gè)軟件工程問題:從一臺(tái)機(jī)器調(diào)用另一臺(tái)機(jī)器上的服務(wù)或方法,即使這些機(jī)器使用完全不同的硬件或軟件。對(duì)于這個(gè)問題,最近提出的解決方案是Web服務(wù)。幾年前,Web服務(wù)大受吹捧,它的頭上圍繞著耀眼的光環(huán),有些人認(rèn)為Web服務(wù)就是分布式軟件開發(fā)的“圣杯”。后來,它的光芒逐漸黯淡下來,Web服務(wù)最終找到了自己合適的位置,它是支持異構(gòu)計(jì)算機(jī)系統(tǒng)相互操作的一種有用的工具。
Web服務(wù)通常用作為計(jì)算機(jī)系統(tǒng)之間的通信管道,這與CORBA(公共對(duì)象請(qǐng)求代理體系結(jié)構(gòu))、RMI(遠(yuǎn)程方法調(diào)用)或DCOM(分布式組件對(duì)象模型)很相似。區(qū)別在于,Web服務(wù)獨(dú)立于具體的開發(fā)商,可以采用大量編程工具和平臺(tái)來實(shí)現(xiàn)。為了支持更高層次的互操作性,Web服務(wù)是基于文本的協(xié)議,通常在HTTP之上實(shí)現(xiàn)。由于Web服務(wù)是基于文本的協(xié)議,所以幾乎總能使用某種XML。
最著名的Web服務(wù)實(shí)現(xiàn)是SOAP(簡單對(duì)象訪問協(xié)議)。SOAP是由W3C管理的規(guī)約,它是XML協(xié)議,對(duì)于如何調(diào)用遠(yuǎn)程過程給出了定義。
WSDL(Web服務(wù)描述語言)文檔也是XML文檔,描述了如何創(chuàng)建Web服務(wù)的客戶。通過提供WSDL文檔,Web服務(wù)提供者就能很輕松地為可能的客戶創(chuàng)建客戶端代碼。WSDL和SOAP通常一同使用,不過不一定非得這樣,因?yàn)檫@兩個(gè)規(guī)約是分開維護(hù)的。
盡管人們?cè)诤喕疭OAP實(shí)現(xiàn)上做出了很大努力,但SOAP還是一個(gè)很難使用的技術(shù),因此很受“排擠”,只有在跨平臺(tái)互操作性確實(shí)是一個(gè)很重要的需求時(shí)才會(huì)使用SOAP。實(shí)現(xiàn)Web服務(wù)還有一種更簡單的方法,稱為REST(代表狀態(tài)傳輸),它在開發(fā)人員中享有越來越高的知名度,這些開發(fā)人員一方面希望得到SOAP好處的80%,另一方面只希望付出SOAP代價(jià)的20%。
Yahoo!選擇REST作為其公共Web服務(wù)的協(xié)議。Yahoo!認(rèn)為基于REST的服務(wù)很容易理解,而且很推崇REST的“平易近人”,因?yàn)楫?dāng)前大多數(shù)編程語言都可以訪問REST。實(shí)際上,Yahoo!相信,與SOAP相比,REST的門檻更低,使用也更容易。
通過使用REST,建立請(qǐng)求時(shí)可以先指定一個(gè)服務(wù)入口URL,再向查詢串追加搜索參數(shù)。服務(wù)將結(jié)果返回為XML文檔。這個(gè)模式聽上去是不是很熟悉?你說對(duì)了,它與本書中你見過的Ajax例子是一樣的。
XMLHttpRequest對(duì)象非常適合作為基于REST的Web服務(wù)的客戶。使用XMLHttpRequest對(duì)象,可以向Web服務(wù)異步地發(fā)出請(qǐng)求,并解析得到的XML響應(yīng)。對(duì)于Yahoo! Web服務(wù),XMLHttpRequest對(duì)象可以向Yahoo!發(fā)出請(qǐng)求,搜索指定的項(xiàng)。一旦Yahoo!返回響應(yīng),則使用JavaScript DOM方法解析響應(yīng),并向頁面動(dòng)態(tài)地提供結(jié)果數(shù)據(jù)。
代碼清單4-15展示了如何使用Ajax技術(shù)訪問Yahoo! Web服務(wù),并向頁面提供結(jié)果。頁面上的文本字段允許用戶指定搜索項(xiàng)。用戶可以使用選擇框來指定需要顯示多少個(gè)結(jié)果。點(diǎn)擊Submit(提交)按鈕就能啟動(dòng)搜索。
不過,先等等!第2章我們?cè)?jīng)說過,XMLHttpRequest對(duì)象只能訪問發(fā)起文檔(即調(diào)用腳本)所在域中的資源。如果試圖訪問其他域的資源,可能因?yàn)闉g覽器的安全限制而失敗。怎么解決呢?
解決辦法有好幾個(gè)。在第2章已經(jīng)了解到,瀏覽器實(shí)現(xiàn)安全沙箱的方式各有不同。IE會(huì)詢問用戶是否允許訪問另一個(gè)域中的資源。Firefox則會(huì)報(bào)告錯(cuò)誤,自動(dòng)失敗,雖然可以用專用于Firefox的JavaScript代碼避免這種行為。
還有一個(gè)選擇,這也是本例中要采用的方法,就是建立Yahoo!的網(wǎng)關(guān),它與XMLHttp-
Request腳本在同一個(gè)域中。由網(wǎng)關(guān)接收來自XMLHttpRequest對(duì)象的請(qǐng)求,并把它轉(zhuǎn)發(fā)到Y(jié)ahoo! Web服務(wù)。Yahoo!做出響應(yīng)返回結(jié)果時(shí),網(wǎng)關(guān)再把結(jié)果路由傳送到瀏覽器。通過使用這種方法,就能避免使用瀏覽器特定的JavaScript。另外,這種方法也更加健壯,因?yàn)槟氵€可以擴(kuò)展網(wǎng)關(guān),讓它支持其他的Web服務(wù)提供者。
代碼清單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" onclick="doSearch();"/>
</form>
<h2>Results:</h2>
<div id="results"/>
</body>
</html>
點(diǎn)擊頁面上的Submit(提交)按鈕將調(diào)用doSearch函數(shù)。這個(gè)函數(shù)使用createQuery- String函數(shù)來創(chuàng)建目標(biāo)URL,createQueryString函數(shù)負(fù)責(zé)把搜索項(xiàng)和顯示的最大結(jié)果數(shù)(即最多顯示多少個(gè)結(jié)果)放在查詢串中。需要注意,參數(shù)名(query和results)都是Yahoo! Search API定義的。
createQueryString函數(shù)創(chuàng)建的查詢串發(fā)送給Yahoo! Search網(wǎng)關(guān)。在這個(gè)例子中,網(wǎng)關(guān)實(shí)現(xiàn)為名為YahooSearchGatewayServlet的Java servlet(見代碼清單4-16)。這個(gè)servlet的目的很簡單,就是轉(zhuǎn)發(fā)對(duì)Yahoo! Search URL的所有請(qǐng)求,并把結(jié)果傳給瀏覽器。當(dāng)然,這個(gè)網(wǎng)關(guān)也可以用其他語言(而不是Java)來實(shí)現(xiàn)。這個(gè)網(wǎng)關(guān)很簡單,在XMLHttpRequest對(duì)象需要訪問其他域中的資源時(shí),這個(gè)網(wǎng)關(guān)確實(shí)能解決問題。
代碼清單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把結(jié)果返回給網(wǎng)關(guān),而且網(wǎng)關(guān)將結(jié)果再轉(zhuǎn)發(fā)給瀏覽器后,會(huì)調(diào)用parse-
SearchResults函數(shù)。這個(gè)函數(shù)從XMLHttpRequest對(duì)象獲取得到的XML文檔,并查找所有標(biāo)記名為Result的元素。
各Result元素傳給parseResult函數(shù)。這個(gè)函數(shù)使用Result元素的子元素Title、Summary、ClickUrl和Url創(chuàng)建內(nèi)容,并增加到頁面。
可以看到,與基于REST的Web服務(wù)結(jié)合使用時(shí),Ajax技術(shù)相當(dāng)強(qiáng)大。如果想在你自己的域中訪問Web服務(wù),用JavaScript就可以完成。否則,當(dāng)訪問其他域的資源時(shí),就要?jiǎng)?chuàng)建外部資源的某種網(wǎng)關(guān),這樣就能避免瀏覽器安全沙箱問題。