一、前言
这一技术能够向服务器请求额外的数据而无须卸载页面,会带来更好的用户体验。
Ajax这一技术的核心是XMLHttpRequest对象(简称XHR)
XHR为向服务器发送请求和解析服务器相应提供了流畅的接口。能够以异步方式从服务器取得更多信息,意味着用户单击后,可以不必刷新页面也能取得新数据。也就是说,可以使用XHR对象取得新数据,然后 再通过DOM将新数据插入到页面中。
虽然名字中包含XML的成分,但Ajax通信与数据格式无关;这种技术就是无需刷新即可从服务器取得数据,但不一定是XML数据。
二、XMLHttpRequest对象
浏览器差异导致在IE中可能会遇到三种不同版本的XHR对象
现在的浏览器大都支持原生的XHR对象
function createXHR(){ if(typeof XMLHttpRequest !="undefined"){ //创建XHR对象 return new XMLHttpRequest(); } else if(typeof ActiveXObject!="undefined"){ //适用于IE7之前的版本 if(typeof arguments.callee.activeXString !="string"){ var versions=["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"],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对象时,要调用的第一个方法是open(),它接受3个参数
- 要发送的请求的类型:get、post等
- 请求的url
- 表示是否异步发送请求的布尔值
xhr.open("get","example.php",false);
- 调用open()方法并不会真正发送请求,而只是启动一个请求以备发送
- 只能向同一个域中使用相同端口和协议的URL发送请求
send()方法
- 一个参数:要作为请求主体发送的数据;如果不需要通过请求主体发送数据,则必须传入null
- 调用该方法后,请求就会被分派到服务器
- 在收到响应后,相应的数据会自动填充XHR对象的属性
- responseText:作为响应主体被返回的文本,无论内容类型是什么
- responseXML:
- 如果响应的内容类型是”text/xml”或”application/xml”,这个属性中将保存包含着响应数据的XML DOM文档
- 对于非XML数据,属性值为null
- status:响应的HTTP状态
- 200:成功的标志。此时,responseText属性的内容已经就绪,而且在内容类型正确的情况下,responseXML也应该能够访问了。
- 304:请求的资源并没有被修改,可以直接使用浏览器中缓存的版本。也意味着响应是有效的。
- statusText:HTTP状态的说明
- readyState属性:表示请求/响应过程的当前活动阶段
- 0:未初始化。尚未open()
- 1:启动。调用open()
- 2:发送。调用send()
- 3:接收。已经接收到部分响应数据
- 4:完成。已经接收到全部响应数据,而且已经可以在客户端使用了
只要上述属性的值发生改变,就会触发一次readystatechange事件。必须在调用open()之前指定onreadtstatechange事件处理程序才能确保跨浏览器兼容性。
上述事件处理程序,不建议使用this对象。如果使用,在有的浏览器中会导致函数执行失败,或者导致错误发生。因此,使用实际的xhr对象实例变量是较为可靠的一种方式。
在接收到响应之前还可以调用abort()方法来取消异步请求。之后xhr对象会停止触发事件,而且也不再允许访问任何与响应有关的对象属性。在终止请求之后,还应该对XHR对象进行解引用操作。且不建议重用xhr对象。
xhr.abort();
var xhr=createXHR(); xhr.onreadystatechange=function(){ if(xhr.readyState==4){ if(xhr.status>=200&&xhr.status<300||xhr.status==304){ alert(xhr.reasponseText); } else{ alert("unsuccessful:"+xhr.status); } } }; xhr.open("get","example.txt",true); xhr.send(null);
HTTP头部信息
每个HTTP请求和响应都会带有相应的头部信息。
默认情况下,在发送xhr请求的同时,还会发送下列头部信息:
- Accept:在浏览器能够处理的内容类型
- Accept-Charset:浏览器能够显示的字符集
- Accept-Encoding:浏览器能够处理的压缩编码
- Accept-Language:浏览器当前设置的语言
- Connection:浏览器与服务器之间连接的类型
- Cookie:当前页面设置的任何Cookie
- Host:发出请求的页面所在的域
- Referer:发出请求的页面的URI
- User-Agent:浏览器的用户代理字符串
使用setRequestHeader()方法,可以设置自定义的请求头部信息。两个参数
- 头部字段的名称
- 头部字段的值
- 在open()之后,send()之前调用
xhr.open("get","example.php","true"); xhr.setRequestHeader("MyHeader","MyValue"); xhr.send(null);
- 服务器在接收到这种自定义的头部信息后,可以执行相应的后续操作
- 建议使用自定义的头部字段名称,否则有可能会影响服务器的响应
- 调用xhr对象的getResponseHeader()方法
- 传入头部字段名称
- 取得相应的响应头部信息
- 调用getAllResponseHeaders()方法,可以取得一个包含所有头部信息的长字符串
GET请求
最常用于向服务器查询某些信息,可以将查询字符串参数追加到URL的末尾,以便将信息发送给服务器。
对XHR而言,位于传入open()方法的URL末尾的查询字符串必须经过正确的编码才行。
使用encodeURICompinent()进行编码,然后才能放到URL的末尾;而且所有名值对都必须由和号(&)分隔
var url="example.php"; function addURLParam(url,name,value){ url+=(url.indexOf("?")==-1?"?":"&"); url+=encodeURIComonent(name)+"="+encodeURIComponent(value); return url; } //添加参数 url=addURLParam(url,"name","Mary"); //初始化请求 xhr.open("get",url,false);
POST请求
通常用于向服务器发送应该被保存的数据。
POST请求的主题可以包含非常多的数据,而且格式不限。
第一步,初始化一个POST请求
xhr.open("post","example.php",true);
第二步,向send()方法中传入某些数据。可以传入XML DOM文档,传入的文档经序列化之后将作为请求主体被提交到服务器;也可以传入任何想发送到服务器的字符串
服务器对POST请求和提交web表单的请求不会一视同仁。因此,服务器端必须有程序来读取发送过来的原始数据。不过,可以使用XHR来模仿表单提交:
- 将Content-Type头部信息设置为application/x-www-form-urlencoded,也就是表单提交时的内容类型
- 以适当的格式创建一个字符串
//把表单中的数据序列化之后发送给服务器 xhr.open("post","example.php",true); xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); var form=document.getElementById("user-info"); xhr.send(serialize(form));
三、XMLHttpRequest 2级
FormData
FormData为序列化表单以及创建与表单格式相同的数据(用于通过xhr传输)提供了便利
创建后可以添加数据,通过append()方法:
- 接收两个参数:键和值
- 分别对应表单字段的名字和字段中包含的值
- 可以添加任意多个
通过向FormData构造函数中传入表单元素,也可以用表单元素的数据预先向其中填入键值对
var data=new FormData(document.forms[0]); data.append("name","mary");
创建了实例后,可以将它直接传给XHR的send()方法
xhr.send(new FormData(form));
优点:不必设置请求头部,xhr对象能够识别传入的数据类型是FormData的实例,并配置适当的头部信息
超时设定
timeout属性:在给其设置一个数值后,如果在规定的时间内浏览器还没有接收到响应,那么就会触发timeout事件,进而会调用ontimeout事件处理程序。仅适用于ie8+
xhr.open("get","timeout.php",true); xhr.timeout(1000);//1秒钟 xhr.ontimeout=function(){ alert("request did not return in a second."); }; xhr.send(null);
overrideMimeType()方法
- 用于重写XHR响应的MIME类型
- 必须在send()方法前调用,才能保证重写响应的MIME类型
xhr.overrideMimeType("texe/xml");
四、进度事件
- 与客户端服务器通信有关的事件
- loadstart:在接收到响应数据的第一个字节时触发
- progress:在接收响应期间持续不断地触发
- error:在请求发生错误时触发
- abort:在因为调用abort()方法而终止连接时触发
- load:在接收到完整的响应数据时触发
- loadend:在通信完成或者触发load、error、或abort事件后触发
- 每个请求都从loadstart事件开始,接下来是一或多个progress事件,然后触发error、abort或load事件中的一个,最后以触发loadend事件结束
load事件
- 不必检查readystate属性了,但是要检查status属性
- event对象浏览器有差异性,所以还是要使用xhr对象变量
progress事件
- 事件处理程序会接收到一个event对象,其target属性是xhr对象,包含三个额外的属性:
- lengthComputable:表示进度信息是否可用的布尔值
- position:表示已经接收的字节数
- totalSize:表示根据Content-Length响应头部确定的预期字节数
在open()方法之前调用onprogress事件处理程序
xhr.onprogress=function(event){ var divstatus=document.getElementById("status"); if(event.lengthComputable){ divstatus.innerHTML="recived"+event.position+"of"+event.totalSize+"bytes"; } }; xhr.open("get","example.php",true); xhr.send(null);