本节简介(异步链接服务器对象)XMLHTTPRequest以及AJAX的简介。

AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML)。 AJAX有四个方面的好处:1.即减轻了服务器的负担。2带来了更好的用户体验。3.基于标准被广泛的支持。4.拥有更好的页面呈现和数据分离。

技术名称 技术说明
javascript javascript是通用的脚本语言,AJAX是用javascript编写的
css 用户界面的样式通过css来修改
DOM DOM通过javascript修改DOM,ajax可以在运行时改变用户界面,或者局部更新页面中的某个节点。
XMLHttpRequest XMLHttpRequest对象 XMLHttpRequest对象允许web程序员从web服务器以后台的方式获取数据。数据的个数通常是XML或者是文本。

从上面我们看出,javascript就想胶水一样将各个部分粘贴在一起,例如通过javascript操作BOM改变刷新用户界面,通过修改className来改变css样式风格

1.异步对象连接服务器

不严谨的说,ajax是一个简单的多线程,它能够是用户在前台多种操作而不间断。ajax异步交互在后台默默的工作着 在web中异步访问是通过XMLHttpRequest对象来实现的,该对象最早是在ie5被作为activeX控件引入的。随后各个浏览器纷纷支持该异步对象,首先必须创建对象。代码如下:

    var xmlHttp;
            function createXMLHrrpRequest() {
                if (window.ActiveXObject)
                    xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
                else if (window.XMLHttpRequest)
                    xmlHttp = new XMLHttpRequest();
            }

该对象是先创建了一个全局变量xmlHttp,留以后函数中使用。另外创建异步对象函数createXMLHrrpRequest()

该过程用到了if语句方法,如果是IE采用window.ActiveXobject方法,如果不是,则用XMLHttpRequest方法创建函数。

 在创建完异步对象后,自然是使用该对象连接服务器,该对象有一系列十分有用的属性和方法。

属性/方法 说明
abort() 取消请求
getAllResponseHeaders() 获取指定的Http头
open(method,url) 创建请求,method指定请求类型,GET POST
send() 发送请求
setRequestHeader() 指定请求的http头
onreadystatechange 发生任何状态变化时的事件控制对象
readyState

请求的状态

0为尚未初始化

1为正在发送请求

2为请求完成

3为请求成功,正接收数据。

4为接收数据成功

responseText 服务器返回文本
responseXML 服务器返回xml
status

服务器返回的http请求响应值,常用的有

200表示请求成功

202表示请求被接收,但处理未完成

400表示错误的请求

404表示资源未找到

500表示内部服务器错误,如aspx代码错误

创建完XMLHttpRequest对象后首先利用open()方法建立一个请求,并向服务器发送,该方法的完整表示式如下:

open(methond,url,asynchronous,user,password)

其中,method表示请求的类型,通长为GET,POST。

url即请求的地址,可以是绝对地址,也可以是相对地址。

asynchronous是一个布尔值,表示是否为异步请求,默认值为异步请求true。

user、password分别为可选的用户名、密码。

创建了异步对象后,要建立一个到服务器的请求可使用如下代码:

xmlHttp.open("GET","1-1.aspx",true);

以上代码用get方法请求的相对地址为9-1.aspx的页面,方式是异步的。在发出了请求后便需要请求的状态readyState属性来判断请求的情况,如果该属性变化了,就会触发onreadystatechange事件,因此通常的代码如下:

<script type="text/javascript">
            xmlHttp.onRecorderStateChange = function(){
                if(xmlHttp.readyState == 4)
                //执行相关代码
            }
        </script>

也就是直接编写onRecorderStateChange的事件函数,如果readyState的状态为4(数据接收成功)则继续操作。但是通常情况下,不但需要判断请求的状态,还要判断服务器返回的状态status,因此上述代码改为

<script type="text/javascript">
            xmlHttp.onRecorderStateChange = function(){
                if(xmlHttp.readyState == 4&& xmlHttp.status==200)
                //执行相关代码
            }
        </script>

以上两段代码仅仅只是建立了请求,还需要使用send()方法来发送请求,该方法的原型如下:

send(body);

改方法仅有一个参数body,它表示要向服务器发送的数据,其格式为查询字符串的形式,例如:

var body = "myName=isaac&age=25";

如果再open中指定的是get方式,则这些参数作为查询字符串提交,如果指定的是post方式,则作为HTTP的POST方法提交。对于send()而言。body参数是必须的,如果不发送任何数据,则可以使用

xmlHttp.send(null)

特别的,如果使用POST方法进行提交请求,那么在发送之前必须使用以下语句来设置HTTP的头,语法如下:

xmlHttp.setRequestHeader("content-Type","application/x-www-form-urlencoded;")

服务器在收到客户端请求之后,根据请求返回相应的结果,这个结果通常为两种形式,一种是文本形式,存储在responseText中;另一种是XML格式,存储在responseXML中。客户端程序可以对前者进行字符串的处理,对后者进行DOM相关的处理,例如可以对服务器返回值做如下的处理:

alert("服务器返回:"+xmlHttp.responseText);

上述整个异步连接服务器的过程如下:

    <body>
        <script type="text/javascript">
            var xmlHttp;
            function createXMLHttpRequest() {
                if (window.ActiveXObject)
                    xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
                else if (window.XMLHttpRequest)
                    xmlHttp = new XMLHttpRequest();
            }
            function startRequest() {
                createXMLHttpRequest();
                xmlHttp.open("GET", "http://study.ahthw.com/ajaxresponse/1-1.aspx", true);
                xmlHttp.onreadystatechange = function() {
                    if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
                        alert("服务器返回: " + xmlHttp.responseText);
                }
                xmlHttp.send(null);
            }
        </script>
        <input type="button" value="测试异步通讯" onClick="startRequest()">
    </body>

实例:http://study.ahthw.com/ajaxresponse/1-1.html

为了解决异步连接ie缓存问题,需要在真实地址加一个与时间毫秒相关的参数,使得每次请求的地址都不一样。而该参数服务器确是不需要的。

var sUrl = "1-1.aspx?"+new Date().getTime();//地址不断变化
        XMLHttp.open("GET",sUrl,true);

http://study.ahthw.com/ajaxresponse/1-2.html

2.GET和POST模式

上面的实例中,除了请求异步服务器以外,并没有向服务器发送额外的数据,通常在html请求中有get和post模式,这两种模式都可以作为异步请求发送数据的方式。

如果是GET请求,则直接把数据放入异步请求的URL地址中,而send方法不发送任何数据,例如:

    var queryString = "firstName=isaac&birthday=0226";
            var sUrl = "1-1.aspx?" + queryString + "&timestamp" + new Date().getTime();
            xmlHttp.open("GET", sUrl);
            xmlHttp.send(null); //该语句只发送null

如果是POST模式,则是把数据统一在send()方法中送出,请求地址没有任何信息,并且必须设置请求的文件头,例如:

<script language="javascript">
            var queryString = "firstName=isaac&birthday=0226";
            var sUrl = "1-1.aspx?" + queryString + "&timestamp" + new Date().getTime();
            xmlHttp.open("POST", sUrl);
            xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
            xmlHttp.send(queryString); //该语句负责发送数据
        </script>

实例

为了更清楚地演示GET和POST的区别,编写示例代码,首先创建两个文本框用于输入用户姓名和生日,并建立两个按钮分别用于GET和POST两个方法来发送异步请求

<form>
            <p><input type="text" id="firstName"/></p>
            <p><input type="text" id="birthday" /></p>
        </form>
        <input type="button" value="GET" onClick="doRequestUsingGET()">
        <input type="button" value="POST" onClick="doRequestUsingPOST()">

其中用户填写的数据统一用函数createQueryString()编写,需要时予以调运,代码如下

function crrateQueryString() {
                var firstName = document.getElementById("firstName").value;
                var birthday = document.getElementById("birthday").value;
                var queryString = "firstName=" + firstName + "&birthday=" + birthday;
                return queryString;
            }

服务器接收到请求数据后根据不同的时刻返回相应的文本,客户端接收到文本后显示在相应的div快中,代码如下

    function handleStateChange() {
                if (xmlHttp.readyState == 4 && xmlHttp.state == 200) {
                    var responseDiv = document.getElementById("serverResponse");
                    responseDiv.innerHTML = xmlHttp.responseText;
                }
            }

GET和POST各建立自己的函数doRequestUsingGET()和doRequestUsingPOST()。

完整代码如下:

<script type="text/javascript">
            var xmlHttp;

            function createXMLHttpRequest() {
                if (window.ActiveXObject)
                    xmlHttp = new ActiveXObject("Microsoft.XMLHttp");
                else if (window.XMLHttpRequest)
                    xmlHttp = new XMLHttpRequest();
            }

            function createQueryString() {
                var firstName = document.getElementById("firstName").value;
                var birthday = document.getElementById("birthday").value;
                var queryString = "firstName=" + firstName + "&birthday=" + birthday;
                return encodeURI(encodeURI(queryString)); //两次编码解决中文乱码问题
            }

            function doRequestUsingGET() {
                createXMLHttpRequest();
                var queryString = "1-3.aspx?";
                queryString += createQueryString() + "&timestamp=" + new Date().getTime();
                xmlHttp.onreadystatechange = handleStateChange;
                xmlHttp.open("GET", queryString);
                xmlHttp.send(null);
            }

            function doRequestUsingPOST() {
                createXMLHttpRequest();
                var url = "1-3.aspx?timestamp=" + new Date().getTime();
                var queryString = createQueryString();
                xmlHttp.open("POST", url);
                xmlHttp.onreadystatechange = handleStateChange;
                xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                xmlHttp.send(queryString);
            }

            function handleStateChange() {
                if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
                    var responseDiv = document.getElementById("serverResponse");
                    responseDiv.innerHTML = decodeURI(xmlHttp.responseText); //解码
                }
            }
        </script>
        <form>
            <input type="text" id="firstName" />
            <br>
            <input type="text" id="birthday" />
        </form>
        <form>
            <input type="button" value="GET" onclick="doRequestUsingGET();" />
            <br>
            <input type="button" value="POST" onclick="doRequestUsingPOST();" />
        </form>
        <div id="serverResponse"></div>

服务器端主要是根据用户输入以及请求的类型返回不同的字符串

<%@ Page Language="C#" ContentType="text/html" ResponseEncoding="gb2312" %>
<%@ Import Namespace="System.Data" %>
<%
    if(Request.HttpMethod == "POST")
        Response.Write("POST: " + Request["firstName"] + ", your birthday is " + Request["birthday"]);
    else if(Request.HttpMethod == "GET")
        Response.Write("GET: " + Request["firstName"] + ", your birthday is " + Request["birthday"]);
%>

实例:http://study.ahthw.com/ajaxresponse/1-3.html

从以上代码看出POST和GET都发送了数据异步请求,通常在数据不多的时候使用GET,在数据较多的时候使用POST。

在使用PSOT发送中文字符时,post接收会乱码,使用GET发送中文字符正常。这是因为异步对象xmlHttp在处理返回的responseText的时候,是按照UTF-8编码的。
通常的解决办法是escape()对发送的数据进行编码,然后在返回的responseText再使用unescape()进行解码。然而在javascript编程中通常不推荐escape()和unescape()。而推荐使用encodeURI()和decodeURI()。这里要正常运行,必须对发送的数据进行两次encodeURI()编码。
代码如下

    function createQueryString(){
        var firstName =document.getElementById("firstName").value;
        var birthday =document.getElementById("birthday").value;
        var queryString = "firstName="+firstName +"&birthday="+birthday;
        return encodeURI(encodeURI(queryString)); //两次编码解决中文乱码问题
    }

而且在返回数据responeText时再进行一次解码,代码如下

function handleStateChange(){
            if(xmlHttp.readyState==4&&xmlHttp.status ==200){
                var responeDiv =document.getElementById(serverResponse);
                responeDiv.innerHTML = decodeURI(XMLHttp.responseText);//编码
            }
        }

这样POST模式下也能使用中文了。

3.服务器返回xml

XML是一种可扩展标记语言(Extensible Markup Language),它是一种可自定义标记的语言,用来克服html局限,按照实际功能来看,xml主要用于数据存储。

在ajax中,服务器如果返回XML,可通过异步对象的responseXML属性来获取,开发者可以利用DOM的作用方法进行处理。

假设服务器返回

<?xml version="1.0" encoding="gb2312"?>
<list>
    <caption>Member List</caption>
    <member>
        <name>isaac</name>
        <class>W13</class>
        <birth>Jun 24th</birth>
        <constell>Cancer</constell>
        <mobile>1118159</mobile>
    </member>
    <member>
        <name>fresheggs</name>
        <class>W610</class>
        <birth>Nov 5th</birth>
        <constell>Scorpio</constell>
        <mobile>1038818</mobile>
    </member>
    <member>
        <name>girlwing</name>
        <class>W210</class>
        <birth>Sep 16th</birth>
        <constell>Virgo</constell>
        <mobile>1307994</mobile>
    </member>
    <member>
        <name>tastestory</name>
        <class>W15</class>
        <birth>Nov 29th</birth>
        <constell>Sagittarius</constell>
        <mobile>1095245</mobile>
    </member>
    <member>
        <name>lovehate</name>
        <class>W47</class>
        <birth>Sep 5th</birth>
        <constell>Virgo</constell>
        <mobile>6098017</mobile>
    </member>
    <member>
        <name>slepox</name>
        <class>W19</class>
        <birth>Nov 18th</birth>
        <constell>Scorpio</constell>
        <mobile>0658635</mobile>
    </member>
    <member>
        <name>smartlau</name>
        <class>W19</class>
        <birth>Dec 30th</birth>
        <constell>Capricorn</constell>
        <mobile>0006621</mobile>
    </member>
    <member>
        <name>tuonene</name>
        <class>W210</class>
        <birth>Nov 26th</birth>
        <constell>Sagittarius</constell>
        <mobile>0091704</mobile>
    </member>
    <member>
        <name>dovecho</name>
        <class>W19</class>
        <birth>Dec 9th</birth>
        <constell>Sagittarius</constell>
        <mobile>1892013</mobile>
    </member>
    <member>
        <name>shanghen</name>
        <class>W42</class>
        <birth>May 24th</birth>
        <constell>Gemini</constell>
        <mobile>1544254</mobile>
    </member>
    <member>
        <name>venessawj</name>
        <class>W45</class>
        <birth>Apr 1st</birth>
        <constell>Aries</constell>
        <mobile>1523753</mobile>
    </member>
    <member>
        <name>lightyear</name>
        <class>W311</class>
        <birth>Mar 23th</birth>
        <constell>Aries</constell>
        <mobile>1002908</mobile>
    </member>
</list>

下面利用异步对象获取该XML,并将所有的项都罗列在表格中,初始化对象的方法与获取文本完全相同,代码如下:

    var xmlHttp;

            function createXMLHttpRequest() {
                if (window.ActiveXObject)
                    xmlHttp = new ActiveXObject("Mincrosoft,XMLHttp");
                else if (window.XMLHttpRequest)
                    xmlHttp = new XMLHttpRequest();
            }

当用户单击按钮时发生异步请求,并获取responseXML对象,代码如下

    function getXML(addressXML) {
                var sUrl = addressXML + "?timestamp=" + new Date();
                createXMLHttpRequest();
                xmlHttp.onRecorderStateChange = handleStateChange;
                xmlHttp.open("GET", url);
                xml.send(null);
            }

            function handleStateChange() {
                if (xmHttp, readyState == 4 && xmlHttp.status == 200)
                DrawTable(xmlHttp.responseXML); //responseXML获取到xml文档
            }

其中DrawTable()为后勤处理XML的函数,将服务器返回的XML对象responseXML直接作为参数传递,HTML部分如下:

    <input type="button" value="获取XML" onclick="getXML('1-4.xml');"><br><br>
<table class="datalist" summary="list of members in EE Studay" id="member">
    <tr>
        <th scope="col">Name</th>
        <th scope="col">Class</th>
        <th scope="col">Birthday</th>
        <th scope="col">Constellation</th>
        <th scope="col">Mobile</th>
    </tr>
</table>

当用户单击按钮时出发getXML(),并将xml地址1-4.xml作为参数传入

而函数DrawTable()的任务就是把XML中的数据拆分,并重新组装到表格"member"中,代码如下:可以看到处理XML的方法与DOM处理HTML完全相同

    function DrawTable(myXML) {
                //用DOM方法操作XML文档
                var oMembers = myXML.getElementsByTagName("member");
                var oMember = "",
                    sName = "",
                    sClass = "",
                    sBirth = "",
                    sConstell = "",
                    sMobile = "";
                for (var i = 0; i < oMembers.length; i++) {
                    oMember = oMembers[i];
                    sName = oMember.getElementsByTagName("name")[0].firstChild.nodeValue;
                    sClass = oMember.getElementsByTagName("class")[0].firstChild.nodeValue;
                    sBirth = oMember.getElementsByTagName("birth")[0].firstChild.nodeValue;
                    sConstell = oMember.getElementsByTagName("constell")[0].firstChild.nodeValue;
                    sMobile = oMember.getElementsByTagName("mobile")[0].firstChild.nodeValue;
                    //添加一行
                    addTableRow(sName, sClass, sBirth, sConstell, sMobile);
                }
            }

其中addTableRow()函数将拆分出来的每一组XML数据组装成表格<table>的一行,添加到页面中。代码如下:

    function addTableRow(sName, sClass, sBirth, sConstell, sMobile) {
                //表格添加一行的相关操作
                var oTable = document.getElementById("member");
                var oTr = oTable.insertRow(oTable.rows.length);
                var aText = new Array();
                aText[0] = document.createTextNode(sName);
                aText[1] = document.createTextNode(sClass);
                aText[2] = document.createTextNode(sBirth);
                aText[3] = document.createTextNode(sConstell);
                aText[4] = document.createTextNode(sMobile);
                for (var i = 0; i < aText.length; i++) {
                    var oTd = oTr.insertCell(i);
                    oTd.appendChild(aText[i]);
                }
            }

网站中实际返回xml的工作通常是由asp.net jsp php等服务器脚本动态生成的,换句话说,xmlHttp.open()中的URL地址仍然.aspx等动态页面的后缀,它们返回的XML是用户请求生成的。

实例:http://study.ahthw.com/ajaxresponse/1-4.html

4.处理多个异步请求

而实际页面中往往不止一个异步请求,比如在一个表单中,很多单元格都需要发生异步请求来验证,再加上网速的影响,第一个异步请求尚未完成,很可能就已经被第2个请求覆盖。

如:http://study.ahthw.com/ajaxresponse/1-5.html

页面内容不做多介绍,我们发现,发送的第一个请求没有响应,因为它被第二个请求覆盖了。

通常解决的办法是将xmlHttp对象作为局部变量来处理,并且在收到服务器返回值后手动将其删除。如下所示:

        function getData(oServer, oText, oSpan) {
                var xmlHttp; //处理为局部变量
                if (window.ActiveXObject)
                    xmlHttp = new ActiveXObject("Microsoft.XMLHttp");
                else if (window.XMLHttpRequest)
                    xmlHttp = new XMLHttpRequest();
                var queryString = oServer + "?";
                queryString += createQueryString(oText) + "&timestamp=" + new Date().getTime();
                xmlHttp.onreadystatechange = function() {
                    if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
                        var responseSpan = document.getElementById(oSpan);
                        responseSpan.innerHTML = xmlHttp.responseText;
                        delete xmlHttp; //收到返回结构后手动删除
                        xmlHttp = null;
                    }
                }
                xmlHttp.open("GET", queryString);
                xmlHttp.send(null);
            }

实例:http://study.ahthw.com/ajaxresponse/1-6.html

posted on 2015-01-15 17:28  村长很忙  阅读(1508)  评论(4编辑  收藏  举报