Ajax无刷新方法纵览(1)—XMLHttpRequest对象

来源:互联网 发布:java实现n! 编辑:程序博客网 时间:2024/05/22 03:24

一.XMLHttpRequest对象

1.XHR对象的调用及其属性和方法

关于无刷新技术,很自然的会想到XMLHttpRequest(XHR)对象,这是Ajax中请求服务器局部刷新的技术基础,在主流的浏览中都支持XHR,不过是在不同版本和类型的浏览器是用不同的方法获取这个对象。 

var xhr;
try
{xhr= new ActiveXObject('Msxml2.XMLHTTP'); /*IE5.0*/}
catch(e)
{
 try{xhr= new ActiveXObject('Microsoft.XMLHTTP'); /*IE5.5*/}
 catch(e)
 {
  try{xhr= new XMLHttpRequest();/*IE7及其他类型浏览器*/}
  catch(e){}
 }
}

上面利用异常的机制实现了浏览器的兼容。

XHR有同步和异步两种方式,同步请求时,页面会等待服务器的响应结束才允许用户继续进行其他工作,因此如果这个请求阻塞用户很久,那是很令人失望的。所以,通常使用的是异步请求,让用户可以在等待响应的期间可以继续做其他的。下面是典型的打开一个异步请求并处理的代码。 

xhr.open("get","ajax.aspx?arg=a&arg=b"); //创建请求
xhr.onreadystatechange
=
function() { //注册请求状态改变的处理事件
    
if(xhr.readyState==4
) {
        
if(xhr.status==200
) {
            var text
=
xhr.responseText;
        }      
    }                
}
xhr.send(null);//发送请求

 —open()方法是向服务器发送一个请求的前的准备,使用它可以创建一个请求。其完整的形式是open(method,url,asynchronous,username,password),正如上面的示例,后面三个参数是可选的。第三个参数表示请求是否是异步,不设值时,默认的便是true即异步。第一个参数是发送请求的方式,一般是GET或POST比较常用(其他的还有PUT、DELETE等方法)。

  • GET方法如果传递参数,是用紧跟在"?"后面用"&"分隔开的名值对,作为查询字符串提交。在服务器端处理时一般用request.querystring提取(PHP用$_GET("参数名"))。由于send方法中参数body是必须的,而GET方法下不发送数据到服务器端,所以可以为null。
  • POST方法,实际也是可以在URL中传递查询字符串的,并在服务器端用同样的方法提取。然而使用POST方法,是因为需要发送影响服务器状态或更大量的数据。它发送的数据是send方法中body参数的值,该参数也是查询字符串的形式(这也许比较常见,或者说更容易用标准的方式可以提取,就如同从表单用POST方式提交,而实际上如果不设置请求的头部信息,它可以是任何形式)。在服务器端获取时,一般使用request.form提取(PHP用$_POST("参数名"))需要特别注意的是,由于是CGI风格(表单式的提交)上传浏览器数据,所以需要用setRequestHeader方法设置请求的头部信息,这必须要在send方法前设置。 
            
    xhr.open("post","ajax.aspx")
    xhr.setRequestHeader(
    "Content-Type","application/x-www-form-urlencoded"
    );
    xhr.onreadystatechange
    =
    function() {
        
    if(xmlhttp.readyState==4
    ) {
            
    if(xmlhttp.status==200
    ) {
                var text
    =
    xhr.responseText;
            }      
        }                
    }
    xhr.send(
    "arg=a&arg=b");

—send()方法发送请求。可以发现为XHR对象上注册了一个onreadystatechange事件处理函数。它使得在send方法发送请求后,请求的状态一但发生改变就会触发这个事件。为了使事件发生时可以被接受处理,因此应该将该事件的处理函数的声明放在send方法的前面。实际上open和send方法都会触发onreadystatechange,然而我们比较关心发送请求后的状态改变因此只在send方法前面声明了处理函数就应该足够了。
        (题外话:这似乎让有点不清楚,为什么要在send前面。如果可以明白Javascript是面向对象的语言,那么就会更清楚,这无非是在给成员赋值。用script标签中定义的方法和成员来说明,通常我们可以在JS代码的任何地方直接使用全局的方法或变量。而实际上,任何的在script标签中定义的全局方法或变量都是window类的成员,当浏览器生成window对象后,也可以用"window.方法名或变量名"的方法访问。在页面加载的过程中解释这些全局的成员,实际上是在解析这个window类,不存在定义先后的问题,因为它们在生成window对象后无论定义先后都会成为的对象成员,每一个类的全局成员的调用都是实际上通过"对象.方法名"的方法访问到的,而在上面的XHR对象最开始并不是我们定义的,我们使用第一段代码获得的,它自己定义了如open、send、onreadystatechangereadyState、status这些成员。我们为它定义的onreadystatechange事件处理函数什么时候开始存在,取决于我们在"new XHR对象"声名引用后,什么时候定义的onreadystatechange事件处理的函数。这实际是在给函数的成员赋值,不过是为事件处理函数成员赋了一个匿名函数)

—readyState变量(也可以称为属性)是用于记录下请求的状态。

  • 当XHR对象产生时它的状态为0(对象已经建立但还未初始化)。
  • open方法执行后状态为1(open已被调用)。
  • send方法执行后状态为2(send已被调用)。
  • 请求发送成功状态为3(正在接受数据)。
  • 请求完成时状态为4(请求完成,返回数据已被接收)。

状态1到3在不同的浏览器中的解释不同,但是我们通常比较关心状态4即请求完成。如果onreadystatechange处理中readyState的值为4就可以继续作请求完成的处理了。

—status属性用于对请求结果的判断。status获得服务器返回的HTTP响应状态编码,表示服务器处理请求结果的状态。这些编码和浏览器正常打开一个页面的响应状态编码一样,包括的404(请求资源未找到)和500(内部服务错误)等,而200(请求成功)在一般的浏览页面响应中就是把页面显示出来不会有其他的,而这里我们需要判断是否响应状态是200,如果是就操作响应返回的结果。

—statusText属性获取响应编码的描述,如" Not Found"等。

—responseText属性获取响应返回的文本,它可以是纯文本或HTML片段。它是接受请求的页面处理完成后,输出到请求页面上的结果内容,这和直接用open方法中的URL参数地址访问请求页面是得到同一结果。

—responseXML属性返回XML文档(DOM)对象,只有当服务器端返回一个XML格式的文档才有效,所以以需要为响应设置头部信息。如果请求的是一个.xml后缀的文件,服务器会自动的设置。否则,需要用代码设置,如response.ContentType="text/xml"。因为获取的是一个DOM模型对象,所以可以用DOM模型进行解析和操作。

—abort()方法取消一个请求,并把请求状态重置为0。

—getAllResponseHeaders()方法,获取包含所有响应头部信息的一个字符串,每个信息之间用换行符号分隔。

—getResponseHeader()方法,获取指定的响应头部信息,接受一个参数,是头部信息字段名称的字符串。

—setRequestHeader()方法,指定请求的头部信息。

*其他的属性和方法

  • —responseBody属性(IE6及以下 Olny)获取服务器返回的未经编码的二进制数据,是数组格式。在IE7中已经无法获取该属性。
  • —responseStream属性(IE6及以下 Olny)返回AdodbStream对象,是原始编码的数据流,它的编码形式取决于服务器发送的编码形式,可以是二进制、UTF8等。它还可以读取非文本数据,如图象、应用程序等。这个属性只有在IE才被支持,因为它获取的AdodbStream对象是IE中特有的,在IE中是ActiveX对象注册的,在IE7中AdodbStream已经被禁止,IE6及以下可以直接创建。在其他浏览器下会出错。这个AdodbStream可写,并且可以写入文件到客户的主机上,因此有很大安全隐患,许多的木马开始用AdodbStream对象的方法和属性通过浏览器传播木马(FireFox等浏览器没有这类型ActiveX控件,因此很安全)。其实,可以把responseBody中的二进制数据写入到AdodbStream对象中,与直接从responseStream属性获取对象是一样的。如下面的示例:
      xhr.open(("get","http://website.com/1.exe",true); 
      xhr.send(
    null
    ); 
      var adoStream
    =new ActiveXObject("ADODB.Stream"
    ); 
      adoStream.Type
    =1;//数据流类型,1表示二进制 

      adoStream.Open(); //打开对象
      adoStream.write(xhr.responseBody); //写入数据
      adoStream.SaveToFile("1.exe",2); //第一参数是保存文件的地址;第二参数是保存的方式,1-如果文件不存在就创建,2-如果文件已存在,用数据流覆盖文件中的数据
     adoStream.Close();//关闭对象 
  •  —overrideMimeType()方法(FireFox Only) 是对响应的页面内容以特定编码进行识别。目前,大多数的网页都是UTF8编码。但是,仍然有不少中文网页文件保存使用了GB2312编码,而XHR对像默认的是以UTF8编码识别网页,因此有时访问会产生乱码,FireFox浏览器提供了overrideMimeType方法解决这个问题。
    xhr.open("GET""ajax.aspx");  
    xhr.overrideMimeType(
    "text/html;charset=gb2312");//以gb2312编码识别数据  

    xhr.onreadystatechange = function(){  
    if (xhr.readyState == 4
    )  
        
    if (xhr.status == 200
    )  
            var text
    =
    xhr.responseText; 
    };  
    xhr.send(
    null);  
    遗憾的是IE下并没有这个方法。但是,IE也有自己的解决方法,其中主要的是使用到了IE特有的execScript()浏览器方法。该方法接受两个字符串参数:第一个参数是脚本的代码字符串,第二是代码的脚本语言类型。主要的代码如下:
    function gb2_To_utf8(data){  
        var glbEncode 
    =
     [];  
        gb2utf8_data 
    =
     data;  
        execScript(
    "gb2utf8_data = MidB(gb2utf8_data, 1)""VBScript"); //IE Olny,VBScript是只有IE支持的脚本语言

        var t=escape(gb2utf8_data).replace(/%u/g,"").replace(/(.{2})(.{2})/g,"%$2%$1").replace(/%([A-Z].)%(.{2})/g,"@$1$2");  
        t
    =t.split("@"
    );  
        var i
    =0,j=
    t.length,k;  
        
    while(++i<
    j) {  
            k
    =t[i].substring(0,4
    );  
            
    if(!
    glbEncode[k]) {  
                gb2utf8_char 
    = eval("0x"+
    k);  
                execScript(
    "gb2utf8_char = Chr(gb2utf8_char)""VBScript");  //IE Olny

                glbEncode[k]=escape(gb2utf8_char).substring(1,6);  
            }  
            t[i]
    =glbEncode[k]+t[i].substring(4
    );  
        }  
        gb2utf8_data 
    = gb2utf8_char = null
    ;  
        
    return unescape(t.join("%"
    ));  
    }

    //调用示例

    xhr.open("get""ajax.aspx";  
    xhr.onreadystatechange 
    =
     function(){  
    if (xhr.readyState == 4
    )  
        
    if (xhr.status == 200
    )  
           var text
    =(gb2_To_utf8(xhr.responseBody)); //IE6及以下 Olny,要使用responseBody属性  

    };  
    xhr.send(
    null);  
    这看起来很失望不是吗,IE7就不奏效,当然,还有其他更普遍的方法。不过,如果尽量都用UFT8编码保存网页,就没有这些问题了。

2.运用XHR异步刷新页面

异步刷新页面是发生在成功返回后进行。刷新一般是通过操纵DOM模型(Document Object Module文档对象模型)来实现。DOM模型把文档结构化,每一个结点都是一个对象,这个对象有属性和方法,因此可以对结点进行操作,并且立即反应到浏览器页面上。例如:document.creatElement(elementName)方法可以创建一个指定标记名称的新结点对象,当执行parentElementObject.appendChild(childElenmetObject)方法则可以把一个指定的子结点对象的引用添加到父结点的引用,并且父结点的改变会立即反应到页面上。

实际上,刷新时通常用到的是改变结点的内容,使用innerHTML属性。该属性可以改变并立即呈现在结点标记之间的HTML片段内容。

<html>
<head>
<script type="text/javascript">
var xhr
=creatXMLHttpReauest() //调用创建XHR对象的封装函数,代码略
xhr.open("get","ajax.aspx?arg=a&arg=b"); 
xhr.onreadystatechange
=function() { 
    
if(xhr.readyState==4) {
        
if(xhr.status==200) {
            document.getElementById(
"div1").innerHTML=xhr.responseText;
        }      
    }                
}
xhr.send(
null);
</script>
</head>
<body>
<div id="div1"></div>
</body>
</html>

运行的结果是,页面显示了ajax.aspx页面返回结果,并且把HTML代码解释呈现在页面上。如果没有这段JS代码,页面将是空白。如果把上面的代码写成一个函数,并且在页面上运行后用一个事件触发调用,效果很明显,就是在不知觉的情况下,页面内容发生了变化,这就是异步刷新。

index.html 页面代码

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>ajax</title>
<script type="text/javascript">
function creatXMLHttpReauest()
{
    try{return new ActiveXObject('Msxml2.XMLHTTP'); /*IE5.0*/}catch(e){}
    try{return new ActiveXObject('Microsoft.XMLHTTP'); /*IE5.5*/}catch(e){}
    try{return new XMLHttpRequest();/*IE7及其他类型浏览器*/}catch(e){}
    return null;
}
function getWebRequest()
{
    var xhr=creatXMLHttpReauest() //调用创建XHR对象的封装函数
    xhr.open("get","ajax.html");
    xhr.onreadystatechange=function()
    {
        if(xhr.readyState==4) {
            if(xhr.status==200) {
           
                document.getElementById("panel1").innerHTML=xhr.responseText;
            }     
        }
    }
    xhr.send(null);                 
}
</script>
</head>
<body>
<span id="panel1">1233</span>
<input type="button" onclick="getWebRequest()" value="进行异步请求"/>
</body>
</html>

ajax.html页面代码,注意将这个文件用UTF8编码保存,否则会出现中文乱码。

<h3>异步请求完成,这是来自响应页面的内容</h3>

 3.XHR的调用的探讨

 

 

原创粉丝点击