AJAX是 AsynchronousJavaScript + XML 的简写。 这种技术能够向服务器请求额外的数据而无须卸载页面(即刷新),会带来更好的用户体验。
AJAX的核心为XMLHttpRequest对象(简称xhr),通过提供了向服务器发送请求和解析服务器响应提供了流畅的接口。能够以异步方式从服务器获取更多的信息, 这就意味着, 用户只要触发某一事件, 在不刷新网页的情况下,更新服务器最新的数据。X代表的是XML,但是用AJAX通信时数据与格式无关。
一 创建XMLHttpRequest对象
在很多浏览器中都可以直接创建xhr对象,但是在IE6中却还是要通过ActiveX的方式来创建xhr对象。检测浏览器支不支持直接创建方式,直接alert(typeof XMLHttpRequest),如果返回的是object则说明浏览器支持直接创建xhr对象。而IE6以及一下的浏览器中通过MSXML库来创建,可能会有三个版本。创建xhr对象的兼容方法:
</pre><pre code_snippet_id="352182" snippet_file_name="blog_20140518_1_1513540" name="code" class="javascript"><span style="font-size:18px;">function createXhr() {
if (typeof window.XMLHttpRequest != "undefined") {
return new XMLHttpRequest();
} else if (typeof ActiveXObject != "undefined") {
var version = ["MSXML2.XMLHttp.6.0",
"MSXML2.XMLHttp.3.0",
"MSXML2.XMLHttp"];
for (var i = 0; i < version; i++) {
try {
return new ActiveXObject(version[i]);
} catch (e) {
}
}
throw new Error("您的操作系统或者浏览器不支持XHR对象");
} else {
throw new Error("您的操作系统或者浏览器不支持XHR对象");
}
}</span>
二 使用xhr对象
在上面创建了xhr对象以后,如果要和浏览器进行通信还必须调用两个方法:open()和send()方法。
xhr.open(x1,x2,x3); 这个方法是用来启动一个请求,准备发送数据,三个参数:参数一是提交方式(get或者post);参数二是请求的目标页面,也就是请求的服务器处理程序页面;参数三是一个布尔值,表示同步还是异步,true表示异步请求,false表示同步请求。
xhr.send(x1); 这个方法是真正的数据请求方法,执行这个方法后,数据请求就会提交到服务器中。接收一个参数,作为向服务器请求提供的数据主体,如果不需要则填写null即可,并且必须填写,不能够为空。
当执行send()方法将请求发送出去,然后接到服务器的响应后,会将响应结果自动填充到xhr的属性中,xhr一共有四个属性,意义如下:
属性 | 说明 |
responseText | 作为响应的主体返回的文本内容 |
responseXML | 如果响应的数据类型是“text/xml”或者“application/xml”,这返回的是XML 文档 |
status | 响应的HTTP状态,N个值 |
statusText | HTTP响应状态的说明 |
属性status有很多值,代表了服务器响应的各种状态,简单的几个如下:
状态值 | 状态字符串 | 说明 |
200 | OK | 服务器成功的返回了数据 |
400 | Bad Request | 语法错误,导致服务器端无法识别 |
404 | Not Found | 指定的URL在服务器端找不到 |
500 | Internal Server Error | 服务器端遇到无法处理的错误,占时不能够完成数据请求 |
503 | ServiceUnavailable | 由于服务器过载或维护导致无法完成请求 |
在send()方法发送完成后,就只是需要监听xhr对象的status对象的值,最好是用状态码,对于状态值在跨浏览器的时候可能不一致。如果收到的值为200,则代表服务器端正确的响应了请求。
<span style="font-size:18px;"> //用事件注册函数给按钮btnOne添加了一个点击事件
addEvent(btnOne,'click',function(){
var xhr = createXhr();
xhr.open("get","one.ashx",false); //设置为同步
xhr.send(null);
//当我们发送完成后,如果服务器有数据返回,会自动填充对象XML
if(xhr.status == 200){ //状态码,200表示成功返回数据,其它都是出错
alert(xhr.responseText); //作为响应主体返回的文本
alert(xhr.responseXML); //如果响应主体内容类型是"text/xhr"或"application/xml",则返回包含响应数据的 XML DOM 文档
alert(xhr.status); //返回的HTTP状态
alert(xhr.statusText); //返回的是HTTP状态说明,可能有的浏览器不一样
}else{
alert("返回数据失败:状态码:"+xhr.statue+"状态说明:"+xhr.statueText);
}
})</span>
三 同步和异步
在上面的xhr对象使用中采用的是同步的请求数据的方式。同步请求数据固然简单容易,但是和XML对象的请求一样,同步时会造成堵塞以及缓慢的状况。所有异步才是使用更多的方式。
异步请求中,需要添加一个事件,readystatechange,和请求XML内容一样,这个事件中有一个属性readyState,有几个值,相比请求XML对象文档的时候多了一个:
值 | 状态 | 说明 |
0 | 未初始化 | 尚为调用open()方法,这个值是在open()方法调用之前会输出 |
1 | 启动 | 已经调用open()方法,但是还没有调用send()方法 |
2 | 发送 | 已经调用send()方法,还没有接收到数据的响应 |
3 | 接收 | 已经收到部分数据的响应,还不可以使用 |
4 | 完成 | 已经接收到全部的数据响应,而且可以使用 |
同步请求方式:
见上面一段代码
异步请求方式:
异步请求数据的时候,在readystatechange事件中,监听readyState的值,是否为4,如果为4就代表数据接收完成,然后就可以进行数据的处理,但是这个事件的方法必须要写在send()方法之前,也就是需要先注册事件。而且在send()方法调用之前还可以通过xhr.abort()方法来取消异步请求,放在send()方法之前会报出一个错误,放在 放在 responseText之前会得到一个空值。
<span style="font-size: 18px;"> addEvent(btnTwo,"click",function(){
<span style="white-space:pre"> </span>var xhr = createXhr();
//异步中的事件,必须写在前面,状态1~4和XML中的1~4是一样的,多了一个0,表示还没有发送
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){ //表示响应已经接收完成,而且可以使用数据
if(xhr.status == 200){ //表示服务器正确返回了页面,一切OK
alert(xhr.responseText);
}else{
alert("数据接收出错");
}
}else{
}
}
xhr.open("get","one.ashx",true); //异步提交
//xhr.abort(); //用来取消请求异步提交,这个必须写在send前面,而且如果取消后会抛一个异常
xhr.send(null); //必须要写在事件后面
})</span>
四 GET和POST
在提供服务器请求的过程中,有两种方式,分别是:GET 和 POST。在 Ajax 使用的过程中,GET 的使用频率要比 POST 高。
每一次向服务器请求服务以及服务器返回服务结果的时候,都会包含一个HTTP头信息,这是浏览器和服务器自动添加的,在请求服务的时候,我们可以设置HTTP头信息,但是不能够读取,在接收到服务器的响应后,可以获取HTTP头信息,但是不能够设置HTTP头信息
获取单个HTTP头信息的方式:xhr.getResponseHeader("Content-Type");获取HTTP响应信息中的Content-Type属性的值
获取所有HTTP头信息的方式:xhr.getAllResponseHeaders();
设置HTTP头信息的方式:xhr.setResquestHeader("name","value");在HTTP响应的头信息中就会添加一行:name:value,可以通过fireBug等浏览器调试工具来查看
Get请求:
GET 请求是最常见的请求类型,最常用于向服务器查询某些信息。必要时,可以将查询字符串参数追加到 URL 的末尾,以便提交给服务器。如果参数中存在一些特殊字符则需要通过encodeURIComponent来进行编码,Get请求的时候,参数时通过URL 后的问号给服务器传递键值对(name=value)数据,每一组数据之间用 & 来分割,服务器接收到返回响应数据,send()方法中参数值为null。
<span style="font-size:18px;"> addEvent(btnOne,"click",function(){
var xhr = createXhr();
var url = "one.ashx?rand="+Math.random();//添加一个随机数
url = encodeUrl(url,"id","10002");
url = encodeUrl(url,"name","ab$cd"); //编码主要就是针对这种特殊字符和中文
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status == 200){
alert(xhr.responseText);
}else {
alert('获取数据错误!错误代号:' + xhr.status + ',错误信息:' + xhr.statusText);
}
}
}
xhr.open("get",url,true);
xhr.send(null);
})
//对参数进行一个编码
function encodeUrl(url,key,value){
url += url.indexOf('?') >=0 ? '&':'?'; //判断URL中是否包含 ? 号
url += encodeURIComponent(key)+"="+encodeURIComponent(value);
return url;
}</span>
Post请求:
Post请求可以向服务器发送很多的数据,一般在表单的提交上都用的是Post请求方式。Post请求的时候,参数不会跟在URL的后面,而是通过 & 来分割键值对,这个一个字符串整体在send(date);方法中传递给服务器。但是, 向服务器发送 POST 请求由于解析机制的原因, 需要进行特别的处理, 因为POST 请求和 Web 表单提交是不同的,需要使用 XHR 来模仿表单提交。在open()方法之后在send()方法之前需要对请求头进行一个设置,添加一句:xhr.setRequestHeader("Conent-Type","application/x-www-form-urlencoded");
<span style="font-size:18px;"> addEvent(btnTwo,"click",function(){
var xhr = createXhr();
var url = "one.ashx?rand="+Math.random();
var date = "";
date = encodeUrl(date,"id","10021");
date = encodeUrl(date,"name","23%ge");
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.staus == 200){
alert(xhr.responseText);
}else{
alert("请求出错:状态码:"+xhr.status+" 状态说明:"+xhr.statusText);
}
}
}
xhr.open("post",url,true);
//Post访问需要设置头信息
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xhr.send(date);
})
<span style="white-space:pre"> </span>//编码数据
function encodeUrl(date,key,value){
date += date.length>0?'&':"";
date += encodeURIComponent(key);
date += "=";
date += encodeURIComponent(value);
return date;
}</span>
从性能上面来说,GET比Post提交效率要高出很多,相同的数据量下,GET要比POST快上近两倍。
同样,JSON格式的数据也可以通过AJAX来请求:
<span style="font-size:18px;"> addEvent(btnThree,"click",function(){
var xhr = createXhr();
var url = "demo.json?rand"+Math.random(); //添加一个随机数,防止访问缓存的数据
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status == 200){
alert(xhr.responseText);
var json = JSON.parse(xhr.responseText);
alert(json);
}
}
}
xhr.open("get",url,true);
xhr.send(null);
})</span>
三 封装AJAX
封装AJAX时,几个问题:参数多少;请求方式是GET还是POST,同步还是异步。为了解决上面几个方法,传递一个对象过去,这个对象中的包含了请求方式,数据(也是一个对象),同步还是异步,同时还包含一个回调函数。封装的方法是慢慢来修改而成的,不是一次形成
回调函数:封装以后,请求数据的结果是不能够返回的,因为涉及到作用域的问题,作用域是无法返回的。故在传递的参数中,添加一个回调函数,这个回调函数接收一个参数,在封装好的AJAX方法中,当正确接收服务器端的响应数据后,调用这个回调函数,将返回的结果传递到这个回调函数中即可,这样在操作这个返回结果是在调用封装好Ajax方法
封装Ajax:
<span style="font-size:18px;">//封装AJAX
function ajax(box) {
var xhr = createXhr();
if (box.method === "get") {
box.url += box.url.indexOf('?') < 0 ? "?" : "&";
box.url += getDate();
}
if (box.async === true) {
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
callBack();
}
}
}
xhr.open(box.method, box.url, box.async)
if (box.method === "post") {
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send(getDate());
} else {
xhr.send(null);
}
if (box.async === false) {
callBack();
}
//下面俩个方法写在这个Ajax方法中,使封装更好,只是需要调用一个方法即可,但是getDate方法的使用范围就缩小了
//回调方法:这里面主要是判断,数据是否正确接收,多次使用故封装起来
function callBack() {
if (xhr.status == 200) {
//return xhr.responseText 返回的是为空,因为不能够返回作用域
//通过函数的回调来实现结果的返回
box.success(xhr.responseText);//
} else {
box.success("error;状态码:" + xhr.status + ";状态码解释:" + xhr.statusText);
}
}
//名值对编码函数
function getDate() {
var arr = [];
for (var i in box.date) {
arr.push(encodeURIComponent(i) + "=" + encodeURIComponent(box.date[i]));
}
return arr.join("&");
}
}</span>
调用Ajax:
<span style="font-size:18px;">//调用
window.onload = function () {
var btnOne = document.getElementById("btnOne");
//点击按钮的时候请求数据
btnOne.onclick = function () {
var box = {
method: "post",
url: "one.ashx",
date: {
"name": "abcd",
"age": 100
},
async: true,
//用作回调函数,在这里面来操作返回的结果
success: function (res) {
//alert(res);
//若返回的数据位JSON格式
var par = JSON.parse(res);
alert(par[0].title);
}
}
ajax(box);
}
}</span>