XMLHTTP應用教程
XMLhttp 是一種浏覽器對象,可用於模擬http 的GET 和POST 請求。配合JavaScript 可以實現頁面數據在無刷新下的定時數據更新,如果應用在聊天室、文字直播上可以取得較好的視覺效果。
一、使用步驟:
1、 創建XMLHTTP對象
2、 打開與服務端的連接,同時定義指令發送方式,服務網頁(URL)和請求權限等。客戶端通過Open命令打開與服務端的服務網頁的連接。與普通HTTP指令傳送一樣,可以用"GET"方法或"POST"方法指向服務端的服務網頁。
3、 發送指令。
4、 等待並接收服務端返回的處理結果。
5、 釋放XMLHTTP對象
三、XMLHTTP方法:
方法
描述
abort()
停止當前請求
getAllResponseHeaders()
作為字符串返問完整的headers,這裡的header是指從服務器返回的頭部
getResponseHeader("headerLabel")
作為字符串返問單個的header標簽 ,這裡的header是指從服務器返回的頭部
open( bstrMethod, bstrUrl,varAsync,
[bstrUser, bstrPassWord] )
bstrMethod: 數據傳送方式,即GET或POST。
bstrUrl: 服務網頁的URL。
varAsync:是否同步執行。缺省為True,即同步執行,
但只能在DOM中實施同步執行。用中一
般將其置為False,即異步執行。
bstrUser: 用戶名,可省略。
bstrPassWord:用戶口令,可省略。
send( varBody )
varBody:指令集。可以是XML格式數據,也可以是字符串,流,或者一個無符號整數數組。也可以省略,讓指令通過open方法的URL參數代入。 通常情況下,如果是用GET方式提交,可以用 XMLobj.send(null)發送, 因為此時要提交的數據已經放在url後面了
setRequestHeader( bstrHeader,
bstrvalue )
bstrHeader:HTTP 頭(header)
bstrvalue: HTTP 頭(header)的值
如果Open方法定義為POST,可以定義表單方式上傳:
XMLhttp.setRequestHeader( "Content-Type",
"application/x-www-form-urlencoded" )
三、 XMLHTTP屬性:
屬性
描述
onreadystatechange
狀態改變的事件觸發器, 在同步執行方式下獲得返回結果的事件句柄,該句柄最好在send之前定義,否則會出錯。
readyState
對象狀態(integer):
0 = 未初始化
1 = 讀取中
2 = 已讀取
3 = 交互中
4 = 完成
responseText
服務器進程返回數據的文本字符串
responseXML
服務器進程返回數據的兼容DOM的XML文檔對象, 這時你可以直接用DOM操作它了。
status
服務器返回的狀態碼, 如:
404 = "文件末找到"
200 ="成功"
statusText
服務器返回的狀態文本信息
responseStream:
結果返回為IStream流。
四、 示例:
A)
<script language="Javascript">
function getDatal(url, data)
{
var result = null;
var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); //創建XMLHTTPRequest對象
XMLhttp.open("GET",url,false); //使用HTTP GET初始化HTTP請求
//設置頭部信息,讓它用utf-8發送,不然中文可能會亂碼
XMLhttp.setrequestheader("content-type","application/x-www-form-urlencoded");
XMLhttp.onreadystatechange = function()
{
if ( xmlhttp.readyState == 4 && XMLhttp.status == 200 )
result = xmlhttp.responseXML; //得到返回信息
}
XMLhttp.send(data); //發送HTTP請求並獲取HTTP響應
return result; //返回結果
}
</script>
B)
<Html>
<head><title>自動刷新</title>
<script language="Javascript">
function detect()
{
xml = new ActiveXObject("Microsoft.XMLHTTP");
var post="數據數據"; //構造要攜帶的數據
//使用POST方法打開一個到服務器的連接,以異步方式通信
XML.open("POST","link.PHP",false);
XML.setrequestheader("content-length",post.length);
XML.setrequestheader("content-type","application/x-www-form-urlencoded");
XML.send(post); //發送數據
var res = XML.responseText; //接收服務器返回的數據
var list = document.getElementById( "list" );
list.innerText = res;
setTimeout(“detect()”,5000); //每隔5秒鐘輪詢一次
}
</script>
<body onload=”detect()”>
<a id="list"></a>
</body>
</Html>
五、要注意的問題
特別要注意的是由於IE 的Cache 的關系,我們看見的XMLHttp 並不總是最新讀取的那一個,為了讓IE 不啟用Cache,我們發送給IE 一個特殊的Header(這裡的header是指後台處理該請求的頁面),用PHP 實現如下:
header( "Expires: Mon, 26 Jul 1997 05:00:00 GMT" );
header( "Last-ModifIEd: " . gmdate( "D, d M Y H:i:s" ) . "GMT" );
header( "Cache-Control: no-cache, must-revalidate" );
header( "Pragma: no-cache" );
使用JavaScript 實現XMLHttp 的跨浏覽器應用
Mozilla和IE同樣支持 XMLHttpRequest ,不過在使用過程中是不一樣的.
1. Mozilla 浏覽器自帶了 XMLHttpRequest 接口
new XMLHttpRequest()
2. 而 IE 需要使用ActiveX對象來建立.
new ActiveXObject("Microsoft.XMLHTTP") //IE5
new ActiveXObject("Msxml2.XMLHTTP") //IE6+
為了能在多種浏覽器上有一個統一的實現,我們可以用JavaScript 來對不同浏覽器的差異進行封裝。這裡我們采用這樣實現:
Var oHttp = window.ActiveXObject? new ActiveXObject("Microsoft.XMLHTTP"):
new XMLHttpRequest();
這樣,JS 腳本允許我們在IE 、Gecko ( Mozilla/Firefox ) 和Opera 的特定版本使用XMLHttp 。下邊是調整後的loadFragmentInToElement 函數,這個函數在IE6 和Firefox1.0pre 上運行通過。
XMLHttp 中的中文亂碼問題
在默認情況下,XMLHttp 都是使用Utf-8 字符集,而我們使用的多是GB2312 字符集,這就要求我們進行GB2312到Utf-8 的轉碼。PHP 提供了一個可選的專碼模塊,可以實現多種字符集之間的相互轉化。加載這個專碼模塊的方法如下:
打開PHP 配置文件php.ini,將 ;extension=php_mbstring.dll(Linux 是PHP_mbstring.so)前的分號去掉。重新啟動apache 以後,這個模塊就可以使用了。如果有錯誤出現,請檢查擴展目錄的路徑設置是否正確。
加載這個模塊以後,我們就可以使用mb_convert_encoding 函數來轉碼了:
$utf8_string = mb_convert_encoding( $gb_string , 'UTF-8' , 'GB2312' );
將轉碼後的字符輸出就可以看見正確顯示的中文了
發送大量XML數據
在把大量的XML作為POST數據的一部分發送給你的IIS服務器的時候——諸如在ASP表單的TEXTAREA裡——你可能會得到一些沒有預料到的結果。當數據在服務器上被處理的時候,由於你處理數據方式的不同,你最終可能會碰到錯誤。其原因是,當你把數據提交回服務器的時候,POST字段裡有一個(數據)大小的限制。這樣做的目的是為了防止可能的入侵者在實施拒絕服務(denial of service,DOS)的攻擊中向服務器發送超大量的數據。
這一限制也束縛你的能力。但是有辦法解決這個問題。如果你沒被限制在只能夠通過FORM提交來發送數據,那麼你就可以使用XMLHTTP對象(微軟的XML集裡的一個DOM對象)來發送所需要的XML:
var oXMLHTTP = new ActiveXObject("Microsoft.XMLHTTP");
oXMLHTTP.open("POST", "XML_handler.ASP", false);
oXMLHTTP.send(XML_to_send);
如果你被限制在只能夠使用FORM提交,那麼你可以通過提交多個TEXTAREA或者INPUT來跨越這一限制,前面兩者在服務器一接收到這個FORM數據的時候就可以被重新組合在一起:
<script language="JavaScript">
var MAXLEN = 90000;
var oForm = document.createElement("FORM");
oFORM.method = "POST";
oFORM.action = "XML_handler.ASP";
oFORM = document.body.appendChild(oFORM);
var s = document.someForm.txtXML.value;
if (s.length > MAXLEN)
{
while ( s.length > MAXLEN )
{
var o = document.createElement("INPUT");
o.type = "hidden";
o.name = "txtXML";
o.value = s.substr(0, MAXLEN);
oFORM.appendChild(o);
s = s.substr(MAXLEN);
}
var o = document.createElement("INPUT");
o.type = "hidden";
o.name = "txtXML";
o.value = s.substr(0, MAXLEN);
oFORM.appendChild(o);
}
else
{
var o = document.createElement("INPUT");
o.type = "hidden";
o.name = "txtXML";
o.value = s;
oFORM.appendChild(o);
}
</script>
這一段代碼會創建一個新的FORM元素,用來處理數據的提交,並將它放置到BODY元素內。然後,它會檢查即將提交給服務器的XML的長度。這個XML駐留在someForm內部一個叫做txtXML的TEXTAREA裡。
如果這個XML大於90,000字符的MAXLEN,那麼這段代碼就會創建多個隱藏的INPUT(輸入)元素,並把值的屬性設置為90,000個字符的XML數據,或者設置為XML尾部的某個值,從而將這個數據分割成多個部分。如果這個XML的大小小於MAXLEN,那麼這段代碼就只會創建一個INPUT並相應地設置值。然後這個數據就被提交到服務器供處理。
你可能已經注意到,我把相同的名稱——txtXML——指定給新表單的每個字段。這將有助於把XML數據同其他可能會被提交的數據分隔開來,並為重組XML數據提供了一種簡單的方式。在重組數據的時候,你需要一個簡單的循環來連接字段裡的數據.
由於已經為每個FORM元素都創建了一個字段集,所以你可以在同一個名稱的字段裡迭代。只要以適當的順序在客戶端創建FORM元素,你就不需要擔心字段被遍歷的順序。通過FORM的appendChild()方法,這能夠被輕易地實現。
數據在客戶端是按照從左到右、從上到下的順序被提交的,所以當你把INPUT元素附加到FORM元素尾部的時候,在你服務端也總是按照同樣的順序來接收數據的。
如果你正在尋求實現一個大型的數據解決方案,例如將大量的Excel數據從客戶機器傳遞到服務器上,那麼你就應該重新考慮是否要使用FORM提交,或者將數據從邏輯上分成多個小的部分。由於你無法使用文件類型INPUT元素,所以最具有創造力的解決方案是將數據在本地轉變成為XML,再將XML數據提交給服務器。反過來,數據會保存在服務器上,直到需要更進一步處理。
當然,處理這個問題可能會有更好的方法。但是當你沒有太多時間的時候,你所需要的就是一個快速的、可用的解決方案。
var objDom = new ActiveXObject("MICROSOFT.XMLDOM")
objDOM.loadXML("<root><action>Inquiry</action><data/></root>");
添加節點到Dom對象objDom
var objNodeChild;
objNodeChild = objDom.createElement(strNodeName); //strNodeName是要新增節點的名稱
objNodeChild.text = strNodeValue; //strNodeValue是要新增節點的值
//strNodeParent是要添加節點的父節點的路徑;
objDom.selectSingleNode(strNodeParent).appendChild(objNodeChild);
//或者是添加屬性到存在的節點
var objNewAttr;
objNewAttr = objDom.createAttribute(strAttrName)
objNewAttr.text = strAttrValue
objDom.selectSingleNode(strNode).Attributes.setNamedItem(objNewAttr)
使用XMLHttp
//創建XMLHttp對象
var objHttp = new ActiveXObject("MICROSOFT.XMLHTTP");
objHttp.open("POST",strASPPageName,false); //false 代表不異步處理
objHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
//傳遞Dom對象到指定頁面
objHttp.send(objDom);
//接受指定頁面處理之後的Dom對象
objDom.load(objHttp.ResponseStream);
//之後就可以對objDom中的數據進行操作
XML介紹之二十八:XMLHTTP: 網站超級粘合劑
簡介
許多ASP開發者都希望在自己的網站中能夠使用到微軟提供的支持XML的新功能。其中,有些人發現可以使用XML來裝飾網站,但是,如果僅僅是只使用XMLDOM的話,你就會失去其他一些更重要的東西。畢竟,XML是用來作為一種網上數據表現和數據交換的形象出現的。
盡管使用XML可以非常滿意地描繪你的數據,但是開發者卻不得不使用CGI來進行浏覽器和服務器之間的數據交換,除非你在浏覽器端和客戶端都使用XML文檔。
當然CGI從傳達信息的角度來說是能夠完全勝任的,但是如果要是和XML來一起使用的話就讓XML失去了很多自己的用處。幸運的是,微軟提供了一種更加有效的方法來傳輸XML,雖然該方法在很大程度上並不被人所重視。
在微軟提供的MSXML解釋器包中有一系列的對象,也許沒有人會重視其中XMLHTTPConnection對象。簡而言之,它允許你打開一個到服務器上的HTTP連接,
發送一些數據和取回一些數據。並且所有的這一切都是在很少的幾段腳本中就能夠實現。
使用XMLHTTP對象通常是進行XML數據交換,但其他格式的數據也是允許的。
這種交換類型的標准模式是客戶端發送一個XML格式的文本字符串到服務端,然後服務端將這個字符串裝載入一個XMLDOM對象中並且解釋它,然後返回一段Html給客戶端,或則是另外一段XML代碼給客戶端讓客戶端的浏覽器自己解釋。
在這種方式下,對於信息的傳遞來說是非常有效的形式,尤其是當你使用DHtml允許你根據返回信息動態顯示時。
舉例如下(只能夠運行在客戶端和服務端都安裝有IE5的情況下)
<%
if (Request.ServerVariables("REQUEST_METHOD") == "POST" )
{
var req = Server.CreateObject("Microsoft.XMLDOM");
req.async = false;
req.load(Request);
if (req.documentElement.nodeName=="timesheet")
{
//對數據隨便進行一些處理。。。
.....
Response.write( "<h1>Timesheet Updated!</h1><b>"
+ req.documentElement.text+"</b>" );
}
}
else
{
%>
<div id="divDisplay">The response will be put in here</div>
<input type="button" value="Send it!">
<script language="JavaScript">
function sendData()
{
var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
XMLhttp.Open("POST", "http://www.yoursite.com/thispage.ASP", false);
XMLhttp.Send("<timesheet>An impossibly useless timesheet fragment</timesheet>");
divDisplay.innerHtml=XMLhttp.responseText;
}
</script>
<%
}
%>
在上面的代碼中,其中客戶端的腳本將建立一個適當的COM對象,打開一個在網站www.yoursite.com的連接(使用了HTTP的POST方法,同步方式),使用Send方法發送一個XML片段,然後根據服務器上的響應填充divDisplay區域(這裡使用了DHtml)。
具體的執行過程是,在服務器上,Request對象被轉載入一個XML文檔然後被解釋器解釋。服務器響應XMLHTTP連接的方式和響應其他任何方式的HTTP連接是一樣的,也是使用了Response對象。注意的是XMLHTTP本身並不檢查request或則response的有效性,也就是說Request或則Response中的數據可是並不需要一定是XML文檔。
“聰明,”你也許會說。“但是為什麼我們不使用CGI來代替它呢?”呵呵,我們要注意這樣一件事,就是如果使用這種方式進行客戶端--服務端的交互時整個頁面並沒有被刷新。
我們都知道,如果要是通過CGI來做任何事情都必將導致浏覽器接收一個完整的新頁面,而這尤其影響網站上的訪問者,因為他們不得不把所有的時間都用來等候整個頁面下載完畢。
同樣,CGI對於網站服務器來說也是一個負擔,因為它不得不把寶貴的處理器循環周期和帶寬消耗在新頁面的所有部分。如果這樣的操作只是一次或則兩次倒無所謂,但是如果是對任何一個電子商務網站或則一個基於Web的電子郵件系統,這將意味著大量的同樣的基本頁面信息被重復一次又一次的裝載。
同樣,如果是通過CGI在網站運用程序中使用XML,服務端一般都將不得不根據數據來建立XML的文檔,然後才能夠對這些文檔進行自己需要的處理。在這種方式下,服務器將花費大量的精力在處理如何建構這些XML文檔上,尤其是當需要傳送的數據量很大時。
所以如果是讓客戶端的浏覽器來建立這個XML文檔,並且在建立完畢後通過XMLHTTP將最後的產品傳遞給服務器,這將大大減輕服務端的代碼量和負擔。
這種類型的問題的一個例子是給服務器上的XML文檔增加數據。如果是使用CGI的話,那麼就需要頻繁的查詢一個CGI的form,然後才能夠構建一個加入XML文檔的XML節點。而如果是使用XMLHTTP需要做的僅僅是把這個XML節點傳遞給服務端就可以了。
上面說討論的是XMLHTTP基本部分,有關它的詳細例子你可以在Microsoft Developers Network中找到例子 。雖然使用這種通訊方式可以大有作為,我在我自己的運用中僅僅只是使用到了很少的一部分,也許任何一個聰明的開發者都能夠發現更多的運用事例。
使用XMLHTTP而不是CGI(即使是我們心愛的ASP)能夠讓我編寫更多野心勃勃的網站運用程序,因為現在我們所關心的簡單到只是我們需要發送的數據而已。從而使用很少的代碼就能夠實現非常復雜的功能,而CGI對於用戶每一個可能的操作都需要我們來完完整整地生成一個新的頁面。
但是由於目前並不是所有的浏覽器都支持MSXML,許多使用ASP編寫的為了非企業內部目的的運用程序需要支持CGI的交互。但是欣慰的是,編寫一個同時支持CGI和XMLHTTP數據的頁面並不是很困難,並且將CGI的數據載入XML文檔中花費的工作量也不是很大。
最簡單的方式來判斷數據是CGI的數據還是XML的數據就是判斷數據的MIME類型.
XMLHTTP的MIME是一個空字符串,除非你特定了其他的MIME類型.
而許多CGI的MIME類型是"application/x-www-form-urlencoded"
下面就是一個來判斷的代碼片段:
<% if (Request.ServerVariables("REQUEST_METHOD") == "POST" )
{
if (Request.ServerVariables("CONTENT_TYPE")=="application/x-www-form-urlencoded")
{
//如果是常規數據(通常編碼是utf-8),讓CGI來處理
Response.write(Request.form("stuff"));
}
else
{
//如果是XMLHTTP連接,將Request對象轉載入XML解釋器
var req= Server.CreateObject("Microsoft.XMLDOM");
req.resolveExternals=false;
req.validateOnParse=false;
req.async=false;
req.load(Request);
Response.write(req.documentElement.selectSingleNode("stuff").text);
}
}
else{ %>
這是一種簡單明了的在同一個ASP頁面中即可以處理CGI也可以處理XMLHTTP數據的方法。並且它也提供了一種能夠兼容在客戶端安裝了IE5.0以及使用其他其他浏覽器浏覽網站的模式。或則也可以采取另外一種方法,就是我對所有的網站運用程序還是采用以前的CGI接口,但是在其他類型的客戶端運用程序使用XMLHTTP方法,例如Microsoft Office運用程序。XMLHTTP的功能並不僅僅局限在浏覽器上,我在Microsoft Office的VBA開發程序中使用XMLHTTP取得了巨大的成功。現在我假設我被要求使用XML技術在更新我公司服務器上的Excel電子表格中的數據。Excel能夠將Html表格直接轉載到自己的表格中,但是它不能夠處理格式復雜的頁面。數據除非使用了非常巧妙的技巧,否則根本沒法插入電子表格。
我的解決方法是編寫了一個ASP頁面來操縱通過XMLHTTP從Excel中傳遞過來的數據。通過一個VBA的宏給服務器發送一個請求,然後將響應載入XML文檔,通過解釋器解釋後再插入Excel的電子表格中。這將是一個無痕的解決方案,簡單的一個按鈕也許會讓你的老板、同事或任何其他人的關系大有改觀。
下面是我實現上述方法的一個代碼片段。它使用XMLHTTP將服務器中的信息載入,然後將其插入電子表格中。
Public Sub UpdateSheet()
Dim XMLhttp
Set xmlhttp = CreateObject("Microsoft.XMLHTTP")
Call XMLhttp.Open("POST", "http://www.yourserver.com/yourpage.ASP", False)
Call XMLhttp.send("<reqtimesheet user='jimbob'/>")
Dim XMLdoc
Set xmldoc = CreateObject("Microsoft.XMLDOM")
XMLdoc.async = False
xmldoc.loadxml(xmlhttp.responseXML)
Worksheets("TimeSheet").Range("A1").Value =
XMLdoc.documentelement.getAttribute("firstname")
Worksheets("TimeSheet").Range("B1").Value =
XMLdoc.documentelement.getAttribute("lastname")
Worksheets("TimeSheet").Range("C37").Value =
XMLdoc.documentelement.selectSingleNode("totalhours").Text
End Sub
這個VBA的宏相當的簡單。給服務器發送一個請求,然後將服務器上的響應插入XML文檔,然後更新Excel中cell中的內容。當然,我們可以使用這個技術做其他更多的運用。例如從一個Office運用程序中上載數據到服務器上的XML文檔中(XML應該是你首選的格式,而不是Office 2000中提供的愚蠢的OfficeXML實現).或則把XML/ASP作為一個你數據庫的shell。這樣,你的運用程序對於數據庫就有了一個簡潔、統一的接口,而對數據庫結構的改動就不必要改動你所有的客戶端代碼了。
我發現XMLHTTP對象在我的編程中非常的有用。我一般使用Visual Basic, Delphi, 和 Visual J++編寫程序,在這個過程中,我經常發現這些語言各自對在線程序處理的方法非常地不同,他們各自有自己的對網絡程序的處理機制,但是如果你要是在處理網絡程序時都使用統一的XMLHTTP連接方式,那麼連接服務器的代碼將非常小,甚至更優化,這是一種對所有的語言都統一的接口。
再來一例:
使用到的是XMLDOM和XMLHTTP對象.用這種技術的好處是:全JS控制,方便/簡單,比RDS或者remote好多了.
function Send(Str,URL)
{
//STR參數是傳入的XML數據,你也可以傳入其他文本數據.
//不過這個函數需要服務器端處理之後返回XML數據,你也可以修改一下
//URL參數表示你所要處理數據的ASP文件地址
var Http = new ActiveXObject("Microsoft.XMLHTTP") //建立XMLHTTP對象
var Dom = new ActiveXObject("Microsoft.XMLDOM") //建立XMLDOM對象
Http.open("POST",URL,false)
//第一個參數的意思是,用"POST"方式發送數據.可以大到4MB,也可以換為"GET".只能256KB
//第2個參數的意思是數據發送到哪個文件處理
//第3個參數意思是同步或異步方式.TRUE為異步,FALSE為同步
Http.send(Str) //開始發送數據.............嘟嘟..
Dom.async=false //設置為同步方式獲取數據
Dom.loadXML(Http.responseText)
//開始獲取服務器端處理後返回的數據.我在這裡設置必須為XML數據,否則出錯.
//你也可以自己修改.使返回的是2進制或者記錄集數據...........................……
if(Dom.parseError.errorCode != 0) //檢查是否發生獲取數據時錯誤
{
delete(Http)
delete(Dom)
return(false)
}
else
{
var Back = Dom.documentElement.childNodes.item(0).text
//得到返回的XML數據,我這裡假設處理程序只返回一行XML數據(一個節點)
delete(Http)
delete(Dom)
return(Back) //函數返回數據.......................結束
}
}
var CAT = Send("<user><name>謝檸檬</name></user>","TEST.PHP"); //執行函數
if (CAT == false)
alert("對不起.處理程序返回的是FALSE.數據處理已經失敗........");
else if( eval(CAT) )
alert("OK.數據已經發送成功.兼以處理完成!!!!!!");
else
alert("對不起.處理程序返回的是FALSE.數據處理已經失敗........");