18.2 AJAX与数据交互
AJAX是运行在浏览器端的技术,它在浏览器端和服务器端之间使用异步技术传输数据。但完整的AJAX的应用还需要服务器端的组件,毕竟浏览器端所有的请求将要由服务器端处理。浏览器端仅仅是通过JavaScript发出请求,并等待服务器的响应,最后处理服务器端传来的数据。服务器端可以使用任何一种语言实现应用,本书中这种语言只能是PHP。本节就向读者介绍AJAX和PHP在Web开发中的结合应用。
18.2.1 创建XMLHttpRequest对象
XMLHttpRequest对象是AJAX的关键所在,也是使用XMLHttpRequest对象是实现AJAX技术的第一步。XMLHttpRequest是一个JavaScript对象,创建该对象很简单,代码如下。
01 <script language="javascript"> 02 var xmlHttp = new XMLHttpRequest(); 03 </script>
【代码解析】这段代码创建了一个XMLHttpRequest对象,并将其赋给JavaScript变量xmlHttp,该变量即代表了XMLHttpRequest对象。但是,由于不同的浏览器使用不同的方法创建XMLHttpRequest对象,例如,IE就使用ActiveXObject。如下JavaScript代码解决了这个问题。
01 var xmlHttp=null 02 if (window.xmlHttpRequest) 03 { 04 xmlHttp=new xmlHttpRequest() 05 } 06 else if (window.ActiveXObject) 07 { 08 xmlHttp=new ActiveXObject("Microsoft.xmlHTTP") 09 }
【代码解析】代码第01行定义了一个变量xmlHttp,将来作为XMLHttpRequest对象来使用,将其赋值为null。然后判断window.xmlHttpRequest对象是否存在,如果存在就创建该对象,否则就创建ActiveXObject对象,如代码第08行所示。这里的参数Microsoft.xmlHTTP是ActiveX对象的ID。
然而,这样创建XMLHttpRequest请求在某些情况下仍然会有问题。因为ActiveXObject方法调用所使用的参数可能会有所不同,除了Microsoft.xmlHTTP,对于更新版本的IE浏览器,该参数就是Msxml2.XMLHTTP。另外,如果试图在浏览器端创建一个不存在的ActiveX对象,应该抛出一个异常。所以,代码18-1是更完整的创建XMLHttpRequest对象的JavaScript程序。
代码18-1 完整的创建XMLHttpRequest对象的JavaScript程序18-1.js
01 function GetXmlHttpRequest() 02 { 03 var xmlHttp=null; 04 try 05 { 06 xmlHttp = new XMLHttpRequest(); // 对于Firefox 等浏览器 07 } 08 catch(e) 09 { 10 try 11 { 12 xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); // 对于IE 浏览器 13 } 14 catch (e) 15 { 16 try 17 { 18 xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); 19 } 20 catch(e) 21 { 22 xmlHttp = false; 23 } 24 } 25 } 26 27 return xmlHttp; 28 }
【代码解析】代码将创建XMLHttpRequest对象的功能封装在一个函数之内。创建XMLHttpRequest对象的步骤如下所述。
(1)建立一个变量xmlHttp来引用即将创建的XMLHttpRequest对象,如代码第03行所示。
(2)尝试在非IE浏览器端创建该对象,如代码第06行所示。如果成功,则不再执行后续代码,变量xmlHttp即为所创建的XMLHttpRequest对象。
(3)如果上步创建失败,则尝试在IE浏览器中使用Msxml2.XMLHTTP创建XMLHttpRequest对象;如果成功,则不再执行后续代码,变量xmlHttp即为所创建的XMLHttpRequest对象。
(4)如果上步失败,再尝试使用Microsoft.XMLHTTP创建该对象;如果成功,变量xmlHttp即为所创建的XMLHttpRequest对象。
(5)如果以上步骤都失败,则该对象赋值为false,表示创建XMLHttpRequest对象失败。
18.2.2 发送异步请求
18.2.1小节向读者介绍了实现AJAX应用的关键一步。之所以说它是关键一步,是因为,正是这个“伟大的”XMLHttpRequest对象将要向Web服务器发出请求,正是这一步实现了通过JavaScript和Web应用程序交互,而不是用户提交给Web服务器的那个HTML表单。
那么,到底如何使用XMLHttpRequest对象向服务器发出请求呢?首先就是要创建一个JavaScript函数,该函数由Web页面调用,比如用户输入数据或者在下拉列表中做了选择时,这个JavaScript函数内将使用XMLHttpRequest对象向服务器发出请求。在实现使用JavaScript向服务器发出请求之前,读者还需要进一步了解XMLHttpRequest对象的一些方法,它们在AJAX应用中发挥着至关重要的作用,读者有必要了解每一个方法,这些方法介绍如下。
·open()方法,基本用法是open(method,url[,async])。open方法会使用method参数所指定的方式(GET或POST)打开(或设置)一个到参数url所指定的连接。可选参数async可以将请求设置为异步或同步,如果该参数值为true,则表示异步,反之为同步,默认值为true,即发起异步请求。该方法还有两个可选参数,因为在本书的实例中不会涉及,这里不再赘述。
·setRequestHeader()方法,用法是setRequestHeader(label,value)。它的作用就是在请求报头中增加一个“标签-值”对。
·send()方法,用法是send(content)。“伟大的”XMLHttpRequest对象将调用同样“伟大的”send()方法向服务器发出请求,send()方法是XMLHttpRequest对象的灵魂所在,就是在这个方法中,JavaScript将请求和数据向服务器发送出去,一切“生动的”应用从这个方法开始。
·getAllResponseHeaders()方法,用法是getAllResponseHeaders(),它获取服务器的所有HTTP响应报头,并将其作为一个字符串返回。这个字符串包含的信息有活动状态的超时时间、内容类型、和服务器有关的信息和日期。
·getReponseHeader()方法,用法是getReponseHeader(label),它获取一个有参数label指定的HTTP响应报头。
·abort()方法,用法是abort(),它用来中止当前的请求。
在了解了XMLHttpRequest对象之后,还有必要认识一下该对象的属性,它在AJAX应用中同样是很重要的。表18-1列举了XMLHttpRequest对象的属性及其含义描述。
表18-1 XMLHttpRequest对象的属性及其含义
在熟悉XMLHttpRequest对象的方法和属性之后,接下来就可以实现使用XMLHttpRequest对象向服务器发出请求的JavaScript函数了。该JavaScript函数假定某个Web页面的Form表单中有个名叫name的文本框,该函数获取该文本框中的数据,并将该数据提交一个名叫getUserName.php的服务器程序,这个程序将处理浏览器提交的数据。因为这里只是将讲解AJAX如何通过JavaScript向服务发出请求,所以并没有实现服务器端的程序,读者在这里需要重点了解XMLHttpReques对象方法的使用。代码18-2为该JavaScript函数的具体实现代码。
代码18-2 发出异步请求的JavaScript程序18-2.js
01 function sendRequest() 02 { 03 // 获取页面表单的文本框name 的值 04 var user_name = document.getElementById("name").value; 05 06 if((user_name == null) || (user_name == "")) 07 return; 08 09 xmlHttp = GetXmlHttpRequest(); 10 if(xmlHttp == null) 11 { 12 alert(" 浏览器不支持XmlHttpRequest !"); 13 return; 14 } 15 16 var url = "getUserName.php"; // 构建请求的URL 地址 17 url = url + "?name=" + user_name; 18 19 xmlHttp.open("GET", url, true); // 使用GET 方法打开一个到url 的连接,为发出请求做准备 20 // 设置一个函数,当服务器处理完请求后调用,该函数名为updatePage 21 xmlHttp.onreadystatechange = updatePage; 22 xmlHttp.send(null); // 发送请求 23 }
【代码解析】这段JavaScript函数完成向服务器发出请求的功能,其中的代码意义都很明确,并没有晦涩难懂的地方,这里做一些简要的解释。代码第04行使用基本的JavaScript代码获取表单文本框元素name的值。在该值有效的情况下,调用18.3.1小节介绍的函数GetXmlHttpRequest()完成XmlHttpRequest对象的创建。如果XmlHttpRequest对象创建成功,则构建一个url地址,这个地址由服务器端处理程序及其需要的参数拼接而成,该地址就是将来要向服务器发起请求的地址。
接着,在代码第19行调用XmlHttpRequest对象的open方法,打开此前建立的url地址,使用GET方法传送数据,并将请求设置为异步方式(open()方法的第3个参数为ture,表示异步请求)。第19行代码中是第1次使用XmlHttpRequest对象。
代码第21行使用了XmlHttpRequest对象的onreadystatechange属性,该属性的作用就是告诉服务器在请求处理完成之后做什么。因为是异步请求,在JavaScript发出请求后并没有等待服务器的响应,所以当服务器完成请求处理,向浏览器发出响应时,应该通知JavaScript,这就是onreadystatechange属性存在的意义。在这个示例中,当服务器完成请求处理,将触发一个名叫updatePage()的JavaScript函数。
代码第22行中XmlHttpRequest对象调用方法send()将请求向服务器发出。
相信读者目前已经意识到AJAX并不是那么神秘,因为AJAX本身没有什么复杂的内容,一切都是按流程化的步骤进行。AJAX所实现的提交表单的办法和传统的方法使用的是相同的技术,不同之处是AJAX通过JavaScript向服务器发出请求并由JavaScript处理响应,还有就是在整个请求和响应过程中页面一直保持着。
在本小节最后总结一下AJAX应用的基本流程,以使读者对AJAX请求部分有更清楚的理解,总结如下所述。
·创建XmlHttpRequest对象。
·在JavaScript函数中获取表单数据。
·建立要连接的URL地址。
·打开到该URL所在服务器的连接。
·设置服务器处理完请求后需要调用的函数。
·发送请求。
18.2.3 编写回调函数
18.2.2小节示例代码的第21行所指定的服务器处理完请求之后所要调用的函数,即所谓的回调函数,JavaScript将在这个函数中完成对服务器返回响应的处理。
XmlHttpRequest对象的readyState属性表示了请求/响应过程中的不同状态。当该属性值为4时,表示响应加载完毕。XmlHttpRequest对象的另一个属性responseText存放了服务器文本格式的响应,也就是说,服务器将请求的处理结果填充到XmlHttpRequest对象的responseText属性中。知道了这两点,完成回调函数就顺理成章、水到渠成了。代码18-3就是处理服务器响应的JavaScript函数的一个实现。
代码18-3 处理服务器响应的JavaScript程序18-3.js
01 function updatePage() 02 { 03 if(xmlHttp.readyState == 4) 04 { 05 var response = xmlHttp.responseText; 06 document.getElementById("userInfo").value = response; 07 } 08 }
【代码解析】这段处理服务器响应的代码看起来要比发出请求的JavaScript代码简单。该函数等待服务器的调用,当服务器处理完请求,就会调用该函数。代码第03行判断XmlHttpRequest对象的readyState属性的值是否为4,如果为4,则通过XmlHttpRequest对象的responseText获取服务器的响应数据,如代码第05行所示。然后通过JavaScript代码将这个服务器响应结果显示到Web页面中,如代码第06行所示。AJAX正是在这里实现了页面没有刷新,但页面内容却被更新的效果。
18.2.4 完整实例
有了以上3个小节的基础知识,读者已经清楚了AJAX内部机制,完全可以在具体的应用中实践AJAX了。这小节将通过一个完整的实例,向读者展示AJAX与PHP程序的具体应用。
这个实例实现的功能是,当用户在Web页面的下拉列表框中选择某个省的名称时,会在页面上显示该省的省会名称,而此时页面并不刷新。省会名称将由服务器端传送至浏览器端。这个完整实例将包含以下3个部分。
·HTML页面,包含下拉列表框和要显示省会名称的位置。
·JavaScript程序,实现发送请求和处理响应。
·服务端的PHP程序,用来接收浏览器的请求,向浏览器传送结果数据。
通常JavaScript程序可以直接写在HTML页面当中,也可以将JavaScript程序单独写在.js文件中,然后在HTML中引用。本例将采用前一种做法。代码18-4就是该HTML页面和JavaScript程序的完整代码。
代码18-4 选择数据HTML页面18-4.html
01 <html> 02 <head> 03 <title>ajax 应用实例</title> 04 05 <script language="javascript"> 06 var xmlHttp = null; 07 08 function GetXmlHttpRequest() 09 { 10 var xmlHttp=null; 11 try // 创建XMLHttpRequest 对象 12 { 13 xmlHttp = new XMLHttpRequest(); 14 } 15 catch(e) 16 { 17 try 18 { 19 xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); 20 } 21 catch (e) 22 { 23 try 24 { 25 xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); 26 } 27 catch(e) 28 { 29 xmlHttp = false; 30 } 31 } 32 } 33 34 return xmlHttp; // 返回XMLHttpRequest 对象 35 } 36 37 function sendRequest() // 发送异步请求 38 { 39 var prov_name = document.getElementById("province").value; 40 41 if((prov_name == null) || (prov_name == "")) 42 return; 43 44 xmlHttp = GetXmlHttpRequest(); 45 if(xmlHttp == null) 46 { 47 alert(" 浏览器不支持XmlHttpRequest !"); 48 return; 49 } 50 51 var url = "18-5.php"; 52 url = url + "?prov=" + prov_name; 53 54 xmlHttp.open("GET", url, true); 55 xmlHttp.onreadystatechange = updatePage; 56 xmlHttp.send(null); 57 } 58 59 function updatePage() // 处理服务器响应 60 { 61 if(xmlHttp.readyState == 4 && xmlHttp.status == 200) 62 { 63 var response = xmlHttp.responseText; 64 document.getElementById("city").innerHTML = response; 65 } 66 } 67 </script> 68 69 <head> 70 71 <body> 72 <h3> 请选择一个省(自治区):</h3> 73 74 <form action="18-5.php"> 75 <div> 76 <select id="province" onchange="sendRequest()"> 77 <option value=""> 请选择一个省(自治区)</option> 78 <option value="ah"> 安徽</option> 79 <option value="fj"> 福建</option> 80 <option value="gs"> 甘肃</option> 81 <option value="gd"> 广东</option> 82 <option value="gx"> 广西</option> 83 <option value="gz"> 贵州</option> 84 <option value="hn"> 海南</option> 85 <option value="hb"> 河北</option> 86 <option value="hh"> 河南</option> 87 <option value="hl"> 黑龙江</option> 88 </select> 89 </div> 90 </form> 91 92 <div id="city"> 93 </div> 94 95 </body> 96 </html>
【代码解析】代码的JavaScript部分就是前面3个小节所讲的AJAX实现步骤的JavaScript函数,这里就不再赘述其功能。代码的HTML部分是在一个表单中加入下拉列表框供用户选择,选择后就会向服务器提交数据,服务器处理完成后回调用updatePage()函数,将结果显示在该HTML页面的ID为“city”的div中,如代码第92行所示。
下面完成服务器端的PHP程序,该程序将获取浏览器端由JavaScript提交的数据,即省份名称,然后在一个数组内找到该省份匹配的省会名称,将该名称返回至浏览器端。代码18-5是完整的服务器端PHP程序。
代码18-5 服务器端处理数据的PHP程序18-5.php
01 <?php 02 $city_arr = array( 03 "ah"=>" 合肥", 04 "fj"=>" 福州", 05 "gs"=>" 兰州", 06 "gd"=>" 广州", 07 "gx"=>" 南宁", 08 "gz"=>" 贵阳", 09 "hn"=>" 海口", 10 "hb"=>" 石家庄", 11 "hh"=>" 郑州", 12 "hl"=>" 哈尔滨" 13 ); 14 15 if(empty($_GET['prov'])) 16 { 17 echo iconv("GB2312","UTF-8",'<font color="red"> 您没有选择省(自治区)</font>'); 18 } 19 else 20 { 21 $prov = $_GET['prov']; 22 $city = $city_arr[$prov]; 23 echo iconv("GB2312","UTF-8",' 所选省(自治区)省会(首府)为:'.$city); 24 } 25 ?>
图18-2 AJAX执行效果图
【代码解析】这是一个很简单的PHP程序,首先定义一个数组用来存储省会名称,然后根据浏览器传入的数据从该数组中取得所对应的省会名称,最后将该数据输出。这里需要解释一下代码第23行,使用了PHP的iconv函数做字符编码转换,如果程序18-5.php使用GB2312编码保存,因为存在汉字字符,在使用JavaScript回调函数时会出现异常,所以这里将编码GB2312转换成UTF-8,以便JavaScript的XMLHttpRequest对象能够正确显示数据。如果程序18-5.php使用了UTF-8编码保存,则不存在这个问题。图18-2是这个实例执行的一个效果图。
本小节实例代码最后向浏览器端响应的是一个字符串结果,并不是XML。这样做只是为了更便于读者理解AJAX的工作原理及使用方法。事实上,服务器的响应是XML才更符合AJAX的本质。如果浏览器端得到的响应是XML,那么在回调函数中就要实现对XML的处理,最终完成页面内容的更新。