Ajax是无需刷新页面就能够从服务器取得数据的一种方法。
关于Ajax,可以从以下几个方面来总结以下:
1)负责Ajax运作的核心对象是XMLHttpRequest对象。
2)XHR对象由微软最早在IE5中引入,用于通过JavaScript从服务器取得XML数据。
3)在此之后,Firefox、Safari、Chrome和Opera都实现了相同的特性,使XHR成为了Web的一个事实标准。
4)虽然实现之间存在差异,但XHR对象的基本用法在不同浏览器还是相对规范的,因此可以放心地用在Web开发中。
同源策略是对XHR的一个主要约束,它为通信设置了“相同的域、相同的端口、相同的协议”这一限制。
试图访问上述限制之外的资源,都会引发安全错误,除非采用被认可的跨域解决方案。
这个解决方案叫做CORS(跨域资源共享),IE8通过XDomainRequest对象支持CORS,其他浏览器通过XHR对象原生支持CORS。图像Ping和JSONP是另外两种跨域通信的技术,但不如CORS稳妥。
Comet是对Ajax的进一步扩展,让服务器几乎能够实时地向客户端推送数据。
实现Comet的手段主要有两个:长轮询和HTTP流。所有浏览器都支持长轮询,而只有部分浏览器原生支持HTTP流。
SSE(服务器发送事件)是一种实现Comet交互的浏览器API,既支持长轮询,也支持HTTP流。
Web Sockets是一种与服务器进行全双工、双向通信的信道。与其他方案不同,Web Sockets不使用HTTP协议,而是用一种自定义的协议。这种协议专门为快速传输小数据设计。虽然要求使用不同的Web服务器,但却有速度上的优势。
各方面对Ajax和Comet的鼓吹吸引了越来越多的开发人员学习JavaScript,人们对Web开发的关注也再度升温。
与Ajax有关的概念都还相对比较新,这些概念会随着时间推移继续发展。
Ajax与Comet
/**
* Ajax 与Comet
*/
function cl(x){
console.log(x);
}
/**
* 21.1 XMLHttpRequest对象
*/
//创建XMLHttpRequest对象
function createXHR(){
if(typeof XMLHttpRequest !="undefined"){ //IE7+ W3C
return new XMLHttpRequest();
}else {
throw new Error("不存在XHR对象");
}
}
var xhr=new createXHR();
//21.1.1 XHR的用法
//在收到响应后,响应的数据会自动填充XHR对象的属性
//responseText:作为响应主体被返回的文本
//responseXML:如果响应的内容类型是"text/xml"或"application/xml",这个属性中将保存包含着响应数据的XML DOM文档。
//status:响应的HTTP状态
//statusText:HTTP状态的说明
//readyState:表示请求响应过程的当前活动阶段
//为确保接收到适当的响应,应该检查是否接收到全部响应数据,以及两种状态代码
xhr.onreadystatechange=function(){
if(xhr.readyState==4){
if((xhr.status>=200 && xhr.status<300) || xhr.status==304){
cl(xhr.responseText);
}else{
cl("Request was unsuccessful:"+xhr.status);
}
}
};
//启动异步请求
xhr.open("get","example.txt",true);
//发送请求
xhr.send(null);
//取消异步请求
xhr.abort();
//21.1.2 HTTP头部信息
//默认情况下,在发送XHR请求的同时,还会发送下列头部信息
//Accept:浏览器能够处理的内容类型
//Accept-Charset:浏览器能够显示的字符集
//Accept-Encoding:浏览器能够处理的压缩编码
//Accept-Language:浏览器当前设置的语言
//Connection:浏览器与服务器之间连接的类型
//Cookie:当前页面设置的任何Cookie
//Host:发送请求的页面所在的域
//Referer:发送请求的页面URI
//User-Agent:浏览器的用户代理字符串
var xhr=new createXHR();
xhr.onreadystatechange=function(){
if(xhr.readyState==4){
if((xhr.status>=200 && xhr.status<300) || xhr.status==304){
cl(xhr.responseText);
}else{
cl("Request was unsuccessful:"+xhr.status);
}
}
};
//启动异步请求
xhr.open("get","example.php",true);
//设置自定义的请求头部信息
xhr.setRequestHeader("myHeader","myValue");
//发送请求
xhr.send(null);
//取得相应的响应头部信息
var myHeader=xhr.getResponseHeader("myHeader");
//取得包含所有头部信息的长字符串
var allHeaders=xhr.getAllResponseHeaders();
//21.1.3 GET请求
xhr.open("get","example.php?name1=value1&name2=value2",true);
//查询字符串中每个参数的名称和值必须使用encodeURIComponent()进行编码
//下面这个函数可以辅助向现有URL的末尾添加查询字符串参数
function addURLParam(url,name,value){
url+=(url.indexOf("?")==-1?"?":"&");
url+=encodeURIComponent(name)+"="+encodeURIComponent(value);
return url;
}
//构建请求URL的事例
var url="example.php";
//添加参数
url=addURLParam(url,"name","Jason");
url=addURLParam(url,"book","Professional JavaScript");
//初始化请求
xhr.open("get",url,true);
//21.1.4 POST请求
//向服务器提交表单数据
function submitData(){
var xhr=new createXHR();
xhr.onreadystatechange=function(){
if(xhr.readyState==4){
if((xhr.status>=200 && xhr.status<300) || xhr.status==304){
cl(xhr.responseText);
}else{
cl("Request was unsuccessful:"+xhr.status);
}
}
};
xhr.open("post","postexample.php",true);
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
var form=document.getElementById("user-info");
xhr.send(serialize(from));
}
//表单序列化的方法
function serialize(form){
var parts=[],
field=null, i,len, j,optLen,option,optValue;
for(i=0,len=form.elements.length;i=200 && xhr.status<300) || xhr.status==304){
cl(xhr.responseText);
}else{
cl("Request was unsuccessful:"+xhr.status);
}
}
};
xhr.open("post","postexample.php",true);
var form=document.getElementById("user-info");
xhr.send(new FormData(form));
//21.2.2 超时设定(IE8+)
//浏览器在规定的时间内没有接收到响应,就会触发timeout事件
var xhr=new createXHR();
xhr.onreadystatechange=function(){
if(xhr.readyState==4){
try{
if((xhr.status>=200 && xhr.status<300) || xhr.status==304){
cl(xhr.responseText);
}else{
cl("Request was unsuccessful:"+xhr.status);
}
}catch(ex){
ontimeout();
}
}
};
xhr.open("get","timeout.php",true);
xhr.timeout=3000;//将超时设置为3秒钟(仅适用于IE8+);
xhr.ontimeout=function(){
alert("请求在3秒内没有回应");
}
xhr.send(null);
//21.2.3 overrideMimeType()方法 (w3c)
//overrideMimeType()用于重写XHR响应的MIME类型
//通过调用overrideMimeType()方法,可以保证把响应当做XML而非纯文本来处理
var xhr=new createXHR();
xhr.open("get","text.php",true);
xhr.overrideMimeType("text/xml");
xhr.send(null);
/**
* 21.3 进度事件
*/
//与客户端服务器通信有关的6个进度事件:
//loadstart:在接收到响应数据的第一个字节时触发
//progress:在接收响应期间持续不断地触发
//error:在请求发生错误时触发
//abort:在因为调用abort()方法而终止连接时触发
//load:在接收到完整的响应数据时触发
//loadend:在通信完成或者触发error、abort或load事件后触发
//21.3.1 load事件
var xhr=new createXHR();
xhr.οnlοad=function(event){
if((xhr.status>=200 && xhr.status<300) || xhr.status==304){
cl(xhr.responseText);
}else{
cl("Request was unsuccessful:"+xhr.status);
}
};
xhr.open("get","altevents.php",true);
xhr.send(null);
//21.3.2 progress事件
//为用户创建进度指示器的一个示例
var xhr=new createXHR();
xhr.οnlοad=function(event){
if((xhr.status>=200 && xhr.status<300) || xhr.status==304){
cl(xhr.responseText);
}else{
cl("Request was unsuccessful:"+xhr.status);
}
};
xhr.οnprοgress=function(event){
var divStatus=document.getElementById("status");
if(event.lengthComputable){
divStatus.innerHTML="Received "+event.position+" of"+event.totalSize+" bytes";
}
}
xhr.open("get","altevents.php",true);
xhr.send(null);
/**
* 21.4 跨域资源共享(CORS)
*/
//CORS背后的基本思想,就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。
//21.4.1 IE对CROS的实现
//XDR对象与XHR的一些不同是:
//cookie不会随请求发送,也不会随响应返回
//只能设置请求头部信息中的Content-Type字段
//不能访问响应头部信息
//只支持GET和POST请求
var xdr=new XDomainRequest();
xdr.οnlοad=function(){
alert(xdr.responseText);
}
xdr.οnerrοr=function(){
alert("An error occurred.");
}
xdr.timeout=3000;
xdr.ontimeout=function(){
alert("Request took too long");
}
xdr.open("post","http://www.somewhere-else.com/page/");
xdr.contentType="application/x-www-form-urlencoded";
xdr.send("name1=value&name2=value2");
//终止请求
xdr.abort();
//21.4.2 其他浏览器对CORS的实现
var xhr=new createXHR();
xhr.onreadystatechange=function(){
if(xhr.readyState==4){
if((xhr.status>=200 && xhr.status<300) || xhr.status==304){
cl(xhr.responseText);
}else{
cl("Request was unsuccessful:"+xhr.status);
}
}
};
xhr.open("get","http://www.somewhere-else.com/page/",true);
xhr.send(null);
//跨域XHR对象为了安全,有一些限制:
//不能使用setRequestHeader()设置自定义头部
//不能发送和接收cookie
//调用getAllResponseHeaders()方法返回空字符串。
//21.4.3 Preflighted Requests (w3c)
//CORS通过一种叫做Preflighted Requests的透明服务器验证机制
// 支持开发人员使用自定义的头部、GET或POST之外的方法,以及不同类型的主体内容
//21.4.4 带凭据的请求 (w3c)
//默认情况下,跨源请求不提供凭据(cookie、HTTP认证及客户端SSL证明等)。
//通过将withCredentials属性设置为true,可以指定某个请求发送凭据。
//21.4.5 跨浏览器的CORS
function createCORSRequest(method,url){
var xhr=new XMLHttpRequest();
if("withCredentials" in xhr){
xhr.open(method,url,true);
}else if(typeof XDomainRequest!="undefined"){
var xhr=new XDomainRequest();
xhr.open(method,url);
}else{
xhr=null;
}
return xhr;
}
var request=createCORSRequest("get","http://www.somewhere-else.com/page/");
if(request){
request.οnlοad=function(){
//对request.responseText进行处理
cl(request.responseText);
};
request.send();
}
/**
* 21.5 其他跨域技术
*/
//21.5.1 图像 Ping
//图像 Ping最常用于跟踪用户点击页面或动态广告曝光次数
//图像 Ping只能用于浏览器与服务器间的单向通信
var img=new Image();
img.οnlοad=img.οnerrοr=function(){
alert("Done!");
};
img.src="http://www.example.com/test?name=Jason";
//21.5.2 JSONP
//JSONP是通过动态