一:什么是Ajax?
Ajax:是对Asychronoous Javascript + XML的简写,是一种和服务器交换数据的技术,这一技术无须刷新页面就可以从服务器取得数据。
但注意,虽然名字中包含XML,但Ajax通信与数据格式无关。
二:XMLHttpRequest对象(简称XHR 本文中简称小X)
该对象是实现Ajax技术的核心,小X能够以异步方式帮我们从服务器取得数据,也就意味着用户单击后,可以不必刷新页面也能取得新数据,也就是说,可以使用XHR对象取得新数据,然后再通过DOM将新数据插入到页面中。
2.1 创建XHR对象
IE7+、Firefox、Opera、Chrome和Safari都支持原生的XHR对象。在这些浏览器中直接调用XMLHttpRequest构造函数来创建即可,如下
var xhr = new XMLHttpRequest();
2.1.1 兼容性问题
如果你想考虑到ie7以下的版本,那么便不能用上面的办法创建XHR对象。
在IE5中,我们的小X是通过MSXML库中一个叫做ActiveX的对象实现的。这便导致了在IE中,我们可能会遇到三个不同版本的XHR对象,分别是MSXML2.XMLHttp、MSXML2.XMLHttp.3.0、MSXML2.XMLHttp.6.0。 那么这时我们如果还想用XHR对象的话,就需要编写一个函数来确定到底要用哪个版本的XHR了。
//适用于IE7以前的版本
function createXHR() {
if(typeof arguments.callee.activeXString != "string") {
var versions = ["MSXML2.XMLHttp", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp6.0"], i, len;
for(i=0, len=versions.length; i<len; i++) {
try{
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
} catch(ex) {
//直接跳过不处理,继续循环
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
}
函数分析:
我们来分析一下这个函数,写的确实很妙,(人家现有的啊,不是我写的啊),arguments.callee指向当前函数体内正在执行的函数,这里就是createXHR函数本身。函数刚进去的时候,当然没有activeXString属性了,所以肯定不等于string,直接进去if,然后将这三个不同的版本名称都放在一个数组中,对每一个版本进行循环,如果当前版本可以用来创建一个ActiveXObject对象,那么我们给当前函数加一个activeXString属性,并赋值为该版本名称,直接跳出循环。如果不能创建ActiveXObject对象,那么就会抛出异常,被catch抓住,不处理,继续循环,直到找到一个能够创建该对象的版本。如果循环完了,三个版本都不能创建ActiveXObject对象,那么就会抛出thrownewError("NoXHRobjectavailable.")的异常,啧,贼惨了这就。
那么这样的话,我们就可以创建一个函数来兼顾所有的浏览器了,我就不信哪位哥还用IE5-。
function createXHR() {
if(typeof XMLHttpRequest != "undefined") {
return new XMLHttpRequest();
} else if(typeof ActiveXObject != "undefined") {
if(typeof arguments.callee.activeXString != "string") {
var versions = ["MSXML2.XMLHttp", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp6.0"], i, len;
for(i=0, len=versions.length; i<len; i++) {
try{
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
} catch(ex) {
//直接跳过不处理,继续循环
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
} else {
throw new Error("No XHR object available.");
}
}
该函数先检测原生XHR对象是否存在,如果存在则直接返回它的新实例。如果原生XHR对象不存在,则检测ActiveX对象,如果都不存在,就抛出一个错误。啧,贼惨了这就。
呼,处理个兼容真烦,万恶的IE!!那么终于我们可以直接一句话创建可爱的小X了
var xhr = createXHR();
2.2 XHR的用法
2.2.1 open()
要调用的第一个方法是open(),它接受三个参数:要发送的请求类型("get", "post"等)、请求的url和表示是否一部发送请求的布尔值。 举个梨子:
xhr.open("get", "haha.php", false); //会启动一个针对haha.php的GET请求,因为是此url为相对路径,相对于当前页面(当然也可以使用绝对路径)
2.2.2 send()
调用open()以后并不会真正发送请求,而只是启动一个请求以备发送。要发送特定请求,必须调用send()方法
xhr.open("get", "haha.php", false);
xhr.send(null);
这里的send()方法接受一个参数,既要作为请求主体发送的数据。如果不需要通过请求主体发送数据,则必须传入null,因为这个参数对有些浏览器来说是必须的。
2.2.3 判断响应状态,接收数据
2.2.3.1 同步请求
由于我们这次的请求是同步的,js代码会等到服务器相应之后在继续执行。在收到响应后,响应的数据会自动填充小X的属性。
responseText: 作为相应主体被返回的文本(即服务器返回的数据)
responseXML: 如果响应的内容类型是“text/xml”或“application/xml”,这个属性中将保存包含响应数据的XML DOM文档。(对于非XML数据来说,该属性为null)
status: 响应的Http状态码
statusText: Http状态的说明
在收到响应后,第一步是检查status的属性,以确定响应是否成功,一般来说以2开头的状态码和304都可表示响应成功。所以检测响应状态的代码如下:
xhr.open("get", "haha.php", false);
xhr.send(null);
if((xhr.status >= 200 && xhr.status <= 300) || xhr.status == 304) {
alert(xhr.responseText); //服务器响应成功
} else {
alert("Request was unseuccessful: " + xhr.status) //服务器响应失败
}
2.2.3.2 异步请求
多数情况下,我们还是要发送异步请求,才能让javascript代码继续执行而不必等待响应。
此时我们可以检测XHR的readyState属性,该属性表示请求/响应过程的当前活动阶段。该属性取值如下:
0:为初始化。尚未调用open()方法。
1:启动。已调用open()方法,但尚未调用send()方法。
2:发送。以调用send()方法,但尚未接受到响应。
3:接受。已经接受到部分相应数据。
4:完成。已经接受到全部相应数据,而且已经可以在客户端使用了。
readystatechange事件
只要readyState的值由一个值变为另一个值,就会触发该事件。利用该事件,我们可以检测当前该请求所处的活动阶段。来看一个梨子:
var xhr = createXHR();
//该事件一定要写在open()方法前面,这样才能确保跨浏览器兼容性
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) { //我们只关心活动阶段为4的值,因为这时所有数据才准备就绪,我们才能用这些数据
if((xhr.status >= 200 && xhr.status <= 300) || xhr.status == 304) {
alert(xhr.responseText); //服务器响应成功
} else {
alert("Request was unseuccessful: " + xhr.status) //服务器响应失败
}
}
}
xhr.open("get", "haha.php", true);
xhr.send(null);
2.2.4 abort()
在接受到响应之前可以调用该方法来取消异步请求。
xhr.abort();
三:怎样发送数据
3.1 GET请求
get是最常见的请求类型,最常用于向服务器查询某些信息。
当xhr对象的请求方式为get时,一般将数据作为查询字符串追加到url的末尾,发送给服务器。但有的人可能总会碰到查询字符串格式有误的问题,这就是我们要注意的,在使用get请求时,查询字符串中每个参数的键和值都要进行encodeURIComponent()编码。才能放到URL末尾。而且所有名-值对之间都必须用&连接。举个梨子:
xhr.open("get", "haha.php?name1=value1&name2=value2", true);
我们来看一个函数:
function addURLParam(url, name, value) { url += (url.indexOf('?') == -1 ? "?" : "&"); url += encodeURIComponent(name) + "=" + encodeURIComponent(value); return url; }
该函数的用途是格式化我们的url,以符合刚才说的查询字符串的要求(上面的红字),建议大家使用该方法,可使查询字符串格式良好,并可靠的用于XHR对象
代码很简单,这里我就不再赘述。上一个使用这个函数构建ajax请求的梨子:
var url = "haha.php" //添加参数 url = addURLParam(url, "name", "Bell"); url = addURLParam(url, "age", "20"); var xhr = createXHR(); xhr.open("get", url, true);
3.2 post请求
post请求通常用于向服务器发送应该被保存的数据。应该把数据作为请求的主体提交。(即放到send中)
post请求发送的数据可以包含非常多的数据,且格式不限。举个梨子
var person = { name: "张三", age: 15 } xhr.send(JSON.stringify(person)); //这里我发一个json过去给服务器
3.3 get和post对比
get post 用途 常用于向服务器查询某些信息 常用于向服务器发送应该被保存的数据 数据格式 查询字符串 格式不限 数据位置 URL末尾 send()函数内部 资源消耗 比get请求消耗的资源会更多一些 性能角度 get请求的速度最多可达到post请求的两倍 数据字节大小(注意这里的限制是对整个url来说的) 最多只能是1024字节 IE对URL长度的限制是2083字节(2K+35)。对于其他浏览器,如Netscape、FireFox等,理论上没有长度限制,其限制取决于操作系统的支持。 安全性 可以从浏览器的历史记录中读取到这些数据,会产生严重的安全问题。 相对来说就可以避免这些问题,个人觉得也没有安全到哪儿去。