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 οnlοad=”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" οnclick="sendData();" 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.数据处理已经失败........");