进入到Web 2.0时代,技术上的特征,很大一部分表现在与用户交互效能的提升。像现在很多流行的电子邮箱的Web界面、Blog程序的界面,都融入了Web 2.0的特征,人们能够像使用C/S架构程序一样使用它们,而不必淹没在没完没了的页面刷新当中。在激动人心的效能提升之前,JavaScript等脚本技术就已经在交互性上发挥了很大的作用。
传统的JavaScript应用局限在对页面内容的控制、与DHTML结合展现网页特效、验证用户输入数据的有效性。在之前也提到过,IFRAME用来在一个页面中显示另外一个页面。将它们结合在一起,就有了初步异步响应机制,用户不必再苦等网页的刷新,就能操纵页面上其他的元素,在服务器端将数据处理好后,会调用IFRAME所在父页面的脚本来刷新父页面元素的内容。
使用JavaScript与IFRAME进行异步响应的示例如例程2-11与例程2-12所示。将例程2-11与例程2-12的程序文件放在相同的文件夹下,就可执行。
例程2-11 用户界面文件index.htm
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>JavaScript与IFRAME异步响应示例</title>
<script language=javascript>
<!--
function getservertime(){
document.frames['ctrframe'].location.replace("getservertime.html");
//在名为ctrframe的IFRAME中打开getservertime.asp文件
}
function msg(){ //后台脚本完成响应后调用的函数
alert("读取成功!");
}
//-->
</script>
</head>
<body>
<span id="servertime">读取服务器时间</span><br>
<input type="button" name="getservertime" id="getservertime" onclick=
"getservertime()"value="读取">
<iframe name=ctrframe id=ctrframe width=0 height=0></iframe>
</body>
</html>
例程2-12 ASP后台处理脚本文件GetServerTime.asp
<%
Dim ServerTime
ServerTime=Now()
%>
<html>
<head></head>
<body>
<input type=hidden name=servertime id=servertime value="<%=ServerTime%>">
<script language=javascript>
<!--
parent.document.getElementById("servertime").innerHTML=document.getElementById
("servertime").value; //使用JavaScript的parent对象更新IFRAME的父页的内容
parent.msg(); //调用父页的响应函数
//-->
</script>
</body>
</html>
那么,有了JavaScript与IFRAME后,为什么还需要Ajax呢?毕竟JavaScript+IFRAME只是一个折中的方案,虽然能够在大部分场合应用,但还是有一些瑕疵。比如使用这种方法时,虽然用户见不到网页的刷新,但是在IE的进度条中依然会显示出IFRAME中页面刷新的进度,单击按钮也会发出当网页刷新或跳转时的音效,让用户依然能够感到页面进行了刷新。况且JavaScript与IFRAME不是专门被设计用来进行异步响应处理的,能够实现简单的文本数据传递,再复杂一些的应用就无能为力了。
对于用户来说这些不是什么大问题,但是对于程序员来说遇到复杂的处理情况,比如不是单单需要简单的文本数据,而是要获取更高级的XML数据,或者更丰富的内容,比如发出一个HEAD请求,获取其他有用的信息时,JavaScript+IFRMAE的方式就不能实现这些高级的功能了。
微软在.NET平台推出了Atlas来配合ASP.NET实现Web 2.0的特性,那么有的朋友又会担心是否ASP将要被淘汰?就目前情况看没有那么糟糕,至少我们还有Ajax能延续ASP的辉煌。
Ajax的核心是基于XMLHttpRequest对象,当然不要被这个对象的名称吓倒,它可以进行XML格式数据的请求,但是在大多数应用情况下,它是使用文本格式的数据进行请求的。使用XMLHttpRequest对象,比使用JavaScript+IFRAME的方式进行异步响应更为干练、更为实用。
[NextPage]
Ajax是Asynchronous JavaScript and XML(及DHTML等)的缩写,它包括以下几个基本技术。
l HTML用于建立Web表单并确定应用程序其他部分使用的字段。
l JavaScript代码是运行Ajax应用程序的核心代码,帮助改进与服务器应用程序的通信。
l DHTML或Dynamic HTML,用于动态更新表单。我们将使用div、span和其他动态HTML元素来标记 HTML。
l 文档对象模型DOM用于(通过JavaScript代码)处理HTML结构和(某些情况下)服务器返回的XML。
看一下使用了Ajax的B/S架构程序与传统的B/S架构程序在客户端和服务器端进行响应的区别,如图2-1所示。
图2-1 Ajax的B/S架构程序与传统的B/S架构程序在客户端和服务器端进行响应的区别
图2-1左半部是传统B/S架构程序的响应机制,客户端(browser client)通过用户接口,(user interface,通常是网页)依靠发送HTTP请求(HTTP Request)直接与服务器(web server)沟通,待服务器读取内容后再返回文本格式的数据(HTML+CSS data),通过用户接口呈现给用户;而使用了Ajax的B/S架构程序在用户接口和服务器端之间增加了Ajax引擎,用户在用户接口通过JavaScript调用Ajax发送请求,服务器端会将数据通过文本或XML格式传送到Ajax引擎,再由Ajax引擎告知用户。这样用户就不必等待页面的刷新,而是由Ajax引擎通过JavaScript来控制页面元素的刷新来更新界面内容。
Ajax使用是比较简单的,抛开XML不说,来看看例程2-13与例程2-14通过Ajax来实现的异步响应。
例程2-13 HTML用户界面文件index.htm
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>AJAX test</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<script language=javascript>
//初始化XMLHttpRequest对象
var request = false;
try {
request = new XMLHttpRequest();
}
catch (trymicrosoft) {
try {
request = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (othermicrosoft) {
try {
request = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (failed) {
request = false;
}
}
}
if (!request){
alert("Error initializing XMLHttpRequest!");
}
function callServer(){
/*从用户页面取得数据*/
var city=document.AJAXtest.city.value;
var state=document.AJAXtest.state.value;
/*数据必须非空*/
if((city==null)||(city==""))return;
if((state==null)||(state==""))return;
/*建立连接字符串*/
var url="GetValueFromClient.asp?city="+escape(city)+"&state=
"+escape(state); //esacape()用来返回为Unicode格式的字串值
/*建立到服务器的连接*/
request.open("GET",url,true) //最后一个参数为true,那么将请求一个异步
//链接,由Ajax来完成。若为false则请求发出后将等待服务器响应
/*设置服务器在完成后要运行的函数*/
request.onreadystatechange=updatePage;
/*发送请求*/
request.send(null); //最后,使用值 null 调用 send()。因为已经在请求
//URL 中添加了要发送给服务器的数据(city 和 state),所以请求中不
//需要发送任何数据。发出请求后,服务器按照您的要求工作
}
function updatePage(){
// 输出就绪状态
/*
try{
alert("updatePage() called with ready state of "
+ request.readyState +" and a response text of '"
+ request.responseText + "'");
}
catch(e1){
alert("Broswer get error.updatePage() called with ready state of "
+ request.readyState)
}
*/
if(request.readyState==4){
/*
0:请求没有发出(在调用 open() 之前);
1:请求已经建立但还没有发出(调用 send() 之前);
2:请求已经发出正在处理之中(这里通常可以从响应得到内容头部);
3:请求已经处理,响应中通常有部分数据可用,但是服务器还没有
完成响应;
4:响应已完成,可以访问服务器响应并使用它。
一些浏览器从不报告0或1而直接从2开始,然后是3和4。
其他浏览器则报告所有的状态。还有一些则多次报告就绪状态1
*/
if(request.status==200){ //HTTP状态码为200代表一切顺利
var response=request.responseText;
document.AJAXtest.result.value=response;
}
else{
switch(request.status){ //输出HTTP状态码
case 403:
alert("Access denied.");
break;
case 404:
alert("Requested URL is not found.");
break;
default:
alert("Error!\nThe HTTP status is:"+request.status);
}
}
}
}
function getHeaders_send(){//发送HEAD请求获取服务器信息
/*从用户页面取得数据*/
var city=document.AJAXtest.city.value;
var state=document.AJAXtest.state.value;
/*数据必须非空*/
if((city==null)||(city==""))return;
if((state==null)||(state==""))return;
var url="GetValueFromClient.asp?city="+escape(city)+"&state="+escape(state);
//esacape()用来返回为Unicode格式的字串值
request.open("HEAD",url,true);
request.onreadystatechange=getHeaders_get;
request.send(null);
}
function getHeaders_get(){
if(request.readyState==4){
alert(request.getAllResponseHeaders());
/*
request.getResponseHeader("Content-Length") 获取响应的长度
request.getResponseHeader("Content-Type") 要获取内容类型
*/
}
}
</script>
</head>
<body>
<form name=AJAXtest>
城市:<input type=text name=city>
<br>
省:<input type=text name=state>
<br>
结果:<input type=text name=result>
<br>
<input type=button value=提交 onclick=callServer()>
<br>
<input type=button value=GetHTTPHeaders onclick=getHeaders_send()>
</form>
</body>
</html>
esacape()方法用来返回Unicode格式的字符串,比如:var tmpstring=esacape ("a test")返回a%20test。 |
在此例程中,不仅演示了使用XMLHttpRequest对象发送GET请求的方法,还演示了发送HEAD请求获取更多服务器信息的方法。
例程2-14 后台脚本处理脚本文件GetValueFromClient.asp
<%
Dim City,State
Dim Result
City=Request.QueryString("City")
State=Request.QueryString("State")
Function GetResult()
Response.CharSet="GB2312"
Result=State&" Province "&City&" City"
Response.Write Result
End Function
GetResult()
%>
在程序中,设置了Response.CharSet属性返回中文,如果不设置Response. CharSet属性为返回中文,则服务器端返回的中文数据都将是乱码。 |
在Ajax的开发中,很多地方都要与DOM(文档对象模型,Document Object Model的缩写)打交道。相信学习过XML的朋友一定不会陌生,对于那些以前没有接触过DOM的朋友,了解它也是很简单的。网页的HTML文档就是基于DOM的,请看例程2-15。
[NextPage]
例程2-15 dom.htm
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>DOM Page</title>
</head>
<body>
<p align=center>这个<i>HTML</i>文档就是基于<strong>DOM</strong>的。</p>
<p>简单的示例。</p>
</body>
</html>
这是一个很简单的网页,里边包含了一些元素,它的结构如图2-2所示。
图2-2 基于DOM的HTML
每一个方框就是一个节点(Node),它拥有父节点和子节点,比如HEAD元素的父节点是HTML,子节点是TITLE和META。最高的一层叫根元素。每个节点还可以拥有自己的属性,比如在第一个节点P中,它拥有一个属性align,值是center。
对DOM的操作是通过JavaScript进行的。
对DOM的操作,包括获取节点对象、添加节点、删除节点、修改节点属性等操作,在此不赘述了,有兴趣的朋友可以去阅读相关资料。
Microsoft的IE使用 MSXML 解析器处理 XML,IE中安装的 JavaScript 技术版本不同,MSXML 实际上有两种不同的版本,因此必须对这两种情况分别编写代码,用来创建XMLHttpRequest对象,参见例程2-16。
例程2-16 在IE中创建XMLHttpRequest对象
var xmlHttp = false;
try {
//尝试使用Msxml2.XMLHTTP名称创建对象
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {
try {
//尝试使用Microsoft.XMLHTTP名称创建对象
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e2) {
xmlHttp = false;
}
}
在非IE的浏览器中,实际就是用一行代码创建对象:
var xmlHttp = new XMLHttpRequest object;
这种方法支持Mozilla、Firefox、Safari、Opera等非IE浏览器。
综合上述方法,整理出在任何浏览器中都可以创建XMLHttpRequest对象的方法,参见例程2-17。
例程2-17 在任何浏览器中都可以创建XMLHttpRequest对象的方法
var xmlHttp = false;
/*@cc_on @*/
/*@if (@_jscript_version >= 5)
//尝试在IE浏览器中创建XMLHttpRequest对象
try {
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {
try {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e2) {
xmlHttp = false;
}
}
@end @*/
//若创建对象失败,则使用非IE浏览器的方法创建XMLHttpRequest对象
if (!xmlHttp && typeof XMLHttpRequest != 'undefined') {
xmlHttp = new XMLHttpRequest();
}
@cc_on语句激活脚本引擎中的条件编译,使不支持条件编译的浏览器将你的脚本视为有效语法而接受它,在注释外的一个@if或@set语句也将激活条件编译。 |
有的朋友尝试把创建XMLHttpRequest对象的代码写入到一个方法当中,当使用的时候可以调用,这种想法是好的,但是忽略了一个问题。如果一个页面有很多内容要填,而用户的浏览器恰好不支持XMLHttpRequest对象,或者因为安全原因关闭了解析JavaScript脚本,那么当用户填完所有信息时才发现页面不能使用,将是一件很恼人的事情。因此建议编写静态的代码,让用户能够尽早发现问题。
可以用XMLHttpRequest对象的readyState获取浏览器的就绪状态码。浏览器就绪状态如下。
l 0:请求没有发出(在调用 open() 之前)。
l 1:请求已经建立但还没有发出(调用 send() 之前)。
l 2:请求已经发出正在处理之中(这里通常可以从响应得到内容头部)。
l 3:请求已经处理,响应中通常有部分数据可用,但是服务器还没有完成响应。
l 4:响应已完成,可以访问服务器响应并使用它。
在多个 JavaScript 函数都使用相同的请求对象时,需要检查就绪状态 0 来确保这个请求对象没有正在使用,这种机制会产生问题。由于 readyState == 4 表示一个已完成的请求,因此使用过程中经常会发现那些目前没在使用的处于就绪状态的请求对象仍然被设置成了4,这是因为从服务器返回来的数据已经使用过了,但是从它们被设置为就绪状态之后就没有进行任何变化。有一个函数 abort() 会重新设置请求对象,但是这个函数却不是真正为了这个目的而使用的。如果程序必须使用多个函数,最好是为每个函数都创建并使用一个函数,而不是在多个函数之间共享相同的对象。
不同的浏览器返回的就绪状态不同。一些浏览器从不报告0或1而直接从2开始,然后是3和4;其他浏览器则报告所有的状态;还有一些则多次报告就绪状态1。这也是需要注意的。比如相同的代码,IE和Firefox 1.5会报告1、2、3、4,而Safari 2.0.1会报告2、3、4,Opera 8.5则只会报告3、4。
初次在ASP中使用XMHttpRequest对象的朋友大多都会碰到一个问题:服务器返回的中文字符串是乱码,这时由于使用XMLHttpRequest对象从服务器返回的字符串默认编码是UTF-8所致,解决的办法就是在ASP脚本中设置Response对象的CharSet属性为中文:
Response.CharSet="GB2312"
若处理用户响应的后台页面出现错误,或者被删除,那么就不能够执行用户的操作。这时就需要根据HTTP状态码来判断错误,以告知用户。可以使用JavaScript的switch…case…default…语句来判断错误代码,并将其转换成错误信息告知用户,如例程2-18所示:
例程2-18 检测HTTP状态码
if(request.status==200){ //HTTP状态码为200代表一切顺利
var response=request.responseText;
document.AJAXtest.result.value=response;
}
else{
switch(request.status){ //输出HTTP错误
case 403:
alert("没有访问权限");
break;
case 404:
alert("页面不存在");
break;
default:
alert("出现错误!\nHTTP状态码:"+request.status);
}
\n的作用是在JavaScript输出的字符串中换行。 |
如对本文有疑问,请提交到交流论坛,广大热心网友会为你解答!! 点击进入论坛