一,XMLHttpRequest对象
IE5是最先引入XHR对象的浏览器,XHR对象是经过MSXML库中的一个ActiveX对象实现的
使用MSXML库中的XHR对象,编写一个函数以下javascript
function ceateXHR(){ if(typeof argument.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(argument.callee.activeXString); }
IE7+,Firefox,Opera,CHrome和safari中支持原生XHR对象,
var xhr = new XMLHttpRequest();
为了兼容以上全部,使用下列函数php
function createXHR(){ if(typeof XMLHttpRequest != "undefined"){ return new XMLHttpRequest(); }else if(typeof ActiveXobject != "undefined"){ if(typeof argument.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]); argument.callee.activeXString = versions[i]; break; }catch(ex){ //跳过 } } } return new ActiveXObject(argument.callee.activeXString); }else{ throw new Error("No XHR object available"); } }
建立对象,var xhr = createXHR();
1,XHR的用法
open(请求的类型(get或post),请求的URL,是否异步发送的布尔值),
要点:URL相对于执行代码的当前页面(可使用绝对路径),open方法不会真的发送请求只是启动一个请求以备发送
send(做为请求主体发送的数据),发送特定的请求,能够传人null,调用函数后请求会被派送到服务器
若是请求时同步的,js代码会等到服务器响应以后执行,响应的数据会自动填充XHR对象的属性
responseText:做为响应主体被返回的文本
responseXML:若是响应的内容类型是text/xml,application/xml,这个属性会保存包含响应数据的XML DOM文档
status:响应的http状态
statusText:http状态的说明
响应后,首先检查status属性,http状态200表示成功,此时responseText属性的内容就绪,内容类型正确的同时,responseXML也能够访问了
状态304表示请求的资源没有被修改,能够直接使用浏览器中缓存的版本,
xhr.open("get","example.text",false);
xhr.send(null);
if((xhr.status >= 200 && xhr.status <= 300) || xhr.status == 304){
alert(xhr.responseText);
}else{
alert("Request was unsuccessful:" + xhr.status);
}
通常状况下使用异步请求,此时js会继续执行没必要等待服务器的响应,此时检测XHR的readyState属性,属性值以下
0:未初始化,还没有调用open方法
1:启动,调用了open方法,未调用send方法
2,发送,调用了send方法,未接受到响应
3,接收,接收到部分响应数据
4,完成,接收到所有的响应数据,并且在客户端使用了
只要readyState属性的值发生变化就会触发readystatechange事件,能够利用这个事件检测每次状态后的readyState的值
必须在open()以前指定onreadystatechange事件处理程序才能保证跨浏览器兼容html
var xhr = createXHR(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if((xhr.status >= 200 && xhr.status <= 300) || xhr.status == 304{ alert(xhr.responseText); }else{ alert("Request was unsuccessful:" + xhr.status); } } }; xhr.open("get","example",true); xhr.send(null);
响应以前调用xhr.abort(),能够取消异步请求,因为内存缘由,不建议重用XHR对象
2,HTTP头部信息
每一个http请求和响应都会带有相应的头部信息,XHR对象也提供了操做这两种头部信息的方式
发送XHR请求的同时,会发送下列头部信息
Accept:浏览器可以处理的内容类型
Accept-Charset:浏览器可以显示的字符集
Accept-Encoding:浏览器可以处理的压缩编码
Accept-Language:浏览器当前设置的语言
Connection:浏览器与服务器之间链接的类型
Cookie:当前页面设置的任何cookie
Host:发送请求的页面所在的域
Referer:发送请求的页面的URL
User-Agent:浏览器的用户代理字符串
setRequestHeader(头部字段的名称,头部字段的值)方法能够自定义设置头部信息,在open和send方法以前调用此方法html5
var xhr = createXHR(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if((xhr.status >= 200 && xhr.status <= 300) || xhr.status == 304){ alert(xhr.reponseText); }else{ alert("Request was unsuccessful :" + xhr.status); } } }; xhr.open("get","example.php",true); xhr.setRequestHeader("MyHeader","MyValue"); xhr.send(null);
调用XHR对象的getResponseHeader()方法,传人头部字段名称,能够返回相应的响应头部信息
getAllResponseHeaders()方法,取得一个包含全部头部信息的长字符串
var myheader = xhr.getResponseHeader("myHeader");
var allheader = xhr.getAllResponseHeader();
服务器端,能够利用头部信息向浏览器发送额外的,结构化的数据,没有自定义的状况下,getAllResponseHeader()方法会返回以下
Date:sun,14 Nov 2004 18:04:03 GMT
Server: Apache/1.3.29(Unix)
Vary:Accept
X-Powered-By:PHP/4.3.8
Connection:close
Content-Type:text/html;charset=iso-8859-1
3,GET请求
用于向服务器查询某些信息,能够将查询字符串追加到URL末尾,
查询字符串,每一个参数的名称和值使用encodeURIComponent()进行编码,并且全部名值对使用&分隔
xhr.open("get","example.php?name1=value&name2=value2",true);
使用下面函数向现有的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","Nicholas");
xhr.open("get",url,true);
4,POST请求
用于向服务器发送应该被保存的数据,
post请求将数据做为请求的主体提交,请求的主体能够包含很是多的数据,格式不限
发送post请求,要向send()方法中传人某些数据,能够是XML DOM文档,可使字符串
XHR模仿表单提交,首先将Content-type头部信息设置为application/x-www-form-urlencoded,而后以适当的格式建立一个字符串,可使用serialize() 函数来建立字符串
function submitData(){
var xhr = createXHR();
xhr.onreadystatechange = function(){
if(xhr.readystate == 4){
if((xhr.status >= 200 && xhr.status <= 300) || xhr.status == 304){
alert(xhr.responseText);
}else{
alert("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(form));
}
php文件经过$_POST取得提交的数据
<?php
header("Content-type:text/plain");
echo <<<EOF
Name:{$_POST["user-name"]}
Email:{$_POST['user-email']}
EOF;
?>
若是不设置Content-type头部信息,那么发送给服务器的数据不会出如今$_POST超级全局变量中,
要访问一样的数据,使用$HTTP_RAW_POST_DATA
二,XMLHttpRequest2级
1,FormData
为了实现表单数据的序列化,FormData类型为序列化表单以及建立与表单格式相同的数据
var data = new FormData();
data.append("name","Nicholas");
append()方法接收两个参数,键值对,
经过向FormData构造函数中传人表单元素,能够用表单元素的数据预先向其中填入键值对
var data = new FormData(document.forms[0]);
建立了FormData实例,直接传给XHR的send()方法java
var xhr = createXHR(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if((xhr.status >= 200 && xhr.status <= 300) || xhr.status == 304){ alert(xhr.responseText); }else{ alert("Request was unsuccessful :" + xhr.status); } } }; xhr.open("post","postexample.php",true); var form = document.getElementById("user-info"); xhr.send(new FormData(form));
XHR对象可以识别传人的数据类型是FormData的实例,并配置适当的头部信息
2,超时设定
XHR对象的timeout属性,表示请求在等待响应多少时间以后就终止,给timeout属性设置一个值,在超过了这个值后,
就会调用ontimeout事件处理程序web
var xhr = createXHR(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ try{ if((xhr.status >= 200 && xhr.status <= 300) || xhr.status == 304){ alert(xhr.responseText); }else{ alert("Request was unsuccessful:" + xhr.status); } }catch(ex){ //假设由ontimeout事件处理程序处理 } } }; xhr.open("get","timeout.php",true); xhr.timoeout = 1000; xhr.ontimeout = function(){ alert("Request did not return in a second."); }; xhr.send(null);
3,overrideMimeType()方法
Firefox最先引入了overrideMimeType()方法,用于重写XHR响应的MIME类型,能够把响应当作XML而非纯文原本处理
var xhr = createXHR();
xhr.open("get","text.php",true);
xhr.overrideMimeType("text/XML");
xhr.send(null);
三,进度事件
Progress Events规范定义了与客户端服务器通讯有关的事件
loadstart:在接收到响应数据的第一个字节时触发
progress:在接收响应期间持续不断的触发
error:在请求发生错误时触发
abort:由于调用abort()方法而终止链接时触发
load:在接收到完整的响应数据时触发
loadend:在通讯完成,或者触发了error,abort,load事件后触发(还没有被任何浏览器支持)
1,load事件
firefox引入了load事件,用于替代readystatechange事件
响应接收完毕后触发load事件,没有必要去检测readyState属性了,
onload会接收到event对象,target属性就指向XHR对象,能够访问到XHR对象的全部方法和属性
对于不支持的浏览器算法
var xhr = createXHR(); xhr.onload = function(){ if((xhr.status >=200 && xhr.status <= 300) || xhr.status == 304){ alert(xhr.responseText); }else{ alert("Request was unsuccessful:" + xhr.status); } }; xhr.open("get","alertEvents.php",true); xhr.send(null);
2,progress事件
事件在浏览器接收数据期间周期性触发,
onprogress事件处理程序会接收到一个evnet对象,其target属性是XHR对象
包含额外的三个属性:lengthComputable(进度信息是否可用的布尔值),position(已经接收的字符数),totalSize(根据Content-Length响应头部肯定的预期字节数)chrome
var xhr = createXHR(); xhr.onload = function(){ if((xhr.status >= 200 && xhr.status <= 300) || xhr.status == 304){ alert(xhr.responsText); }else{ alert("Request was unsuccessful" + xhr.status); } }; xhr.onprogress = function(event){ var divStatus = document.getElementById("status"); if(event.lengthComputable){ divStatus.innerHTML = "Recevied " + event.position + "Of" + event.totalSize + "bytes"; } }; xhr.open("get","alertEvent.php",true); xhr.send(null);
四,跨源资源共享(CORS)
思想是使用自定义的http头部,让浏览器与服务器进行沟通,从而决定请求或响应的成功与否
请求的origin头部,包含请求页面的源信息(协议,域名,端口),
若是服务器认为是可接受的,在Origin-Control-Allow-Origin头部中回发相同的源信息,若是是公共资源,能够回发*
1,IE对CORS的实现
IE8引入XDR类型,相似XHR对象,但能实现安全可靠的跨域通讯,区别以下
cookie不会随请求发送,也不会随响应返回
只能设置请求头部信息中的Content-type字段
不能访问响应头部信息
只支持GET和POST请求
XDR使用方法,建立一个XDomainRequest的实例,调用open()方法,再调用send()方法,
open()方法只接收两个参数,请求类型的UR,XDR请求都是异步的,
请求返回以后会触发load事件,响应的数据保存在responseText属性中
var xdr = new XDomainRequest();
xdr.onload = function(){
alert(xdr.responseText);
};
xdr.open("get","http://www.somewhere-else.com/page/");
xdr.send(null);
接收到响应后,只能访问响应的原始文本,没有办法肯定响应的状态代码,只要响应有效就会会触发load事件,
失败就会触发error事件,遗憾的是,除了错误自己外,没有其余信息可用,所以惟一可以肯定的就是请求未成功,
检测错误能够指定一个onerror事件处理程序
var xdr = new XDomainRequest();
xdr.onload = function(){alert(xdr.responseText)};
xdr.onerror = function(){alert("An error occurred.")};
xdr.open("get","http://www.somewhere-else.com/page/");
xdr.send(null);
返回请求前调用abrot()方法会终止请求
一样支持timeout属性和ontimeout事件
var xdr = new XDomainRequest();
xdr.onload = function(){alert(xdr.responseText);};
xdr.onerror = function(){alert("An Error Occurred");};
xdr.timeout = 1000;
xdr.ontimeout = function(){alert("Request took too long.");};
xdr.open("get","http://www.somewhere-else.com/page/");
xdr.send(null);
为了支持POST请求,XDR对象提供了contenType属性,用来表示发送数据的格式
var xdr = new XDomainRequest();
xdr.onload = function(){};
xdr.onerror = function(){};
xdr.open("post","http://www.somewhere-else.com/page/");
xdr.contentType = "application/x-www-form-urlencoded";
xdr.send("name1=value1&name2=value2");
2,其余浏览器对CORS的实现
经过XMLHttpRequest对象实现对CORS的原生支持,请求另外一个域中的资源,使用标准的XHR对象并在open方法中传人绝对的URLjson
var xhr = createXHR(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if((xhr.status >= 200 && xhr.status <= 300) || xhr.status == 304){ alert("xhr.responseText"); }else{ alert("Request was unsuccessful:" + xhr.status); } } }; xhr.open("get","htt://www.somewhere-else.com/page/",true); xhr.send(null);
跨域XHR对象有限制,
不能使用setRequestHeader()设置自定义头部
不能发送和接受cookie
调用getAllResponseHeader()方法总会返回空字符串
3,Preflighted Request
透明服务器验证机制支持开发人员使用自定义的头部,
使用下列高级选项来发送请求时,就会向服务器发送一个Preflight请求,使用OPTIONS方法,发送下列头部
Origin:与简单的请求相同
Access-Control-Request-Method:请求自身使用的方法
Access-Control-Request-Header:自定义的头部信息,多个头部用逗号分隔
Origin:http://www.nczonline.net
Access-Control-Request-Method:POST
Access-Control-Request-Header:NCZ
发送这个请求后,服务器能够决定是否容许这种类型的请求,服务器经过在响应中发送以下头部与浏览器进行沟通
Access-Control-Allow-Origin:与简单请求相同
Access-Control-Allow-Method:容许的方法,多个方法以逗号分隔
Access-Control-Allow-Header:容许的头部,多个头部以逗号分隔
Access-Control-Max-Age:应该将这个Prefight请求缓存多长时间(秒)
Access-Control-Allow-Origin:http://www.nczonline.net
Access-Control-Allow-Method:POST,GET
Access-COntrol-Allow-Header:NZC
Access-Control-Max-Age:1728000
第一次发送这种请求时会多一个http请求
4,带凭据的请求
默认状况下跨源请求不会提供凭据(cookie,HTTP认证,客户端SSL证实)
经过将withCredentials属性设置为true,能够指定某个请求应该发送凭据
若是服务器端接收带凭据的请求,会使用Access-Control-Allow-Credentials:true来响应
若是服务器的响应中没有这个头部,浏览器就不会把响应交给javascript,responseText中将是空字符串status的值为0,调用onerror事件处理程序
5,跨浏览器的CORS跨域
function createCORSRequest(method,url){ var xhr = new XMLHttpRequest(); if("withCredentials" in xhr){ xhr.open(method,url,true); }else if(typeof XDomainRequest != "undefined"){ vxhr = new XDomainRequest(); xhr.open(method,url); }else{ xhr = null; } return xhr; } var request = createCORSRequest("get","http://www.somewhere-else.com/page/"); if(request){ request.onload = function(){ // }; request.send(); }
firefox,safari,chrome中的XMLHttpRequest对象和IE中XDomainRequest对象相似,共有属性方法以下
abort(),用于中止正在进行的请求
onerror(),用于替代onreadystatechange()检测错误
onload(),用于替代onreadystatechange()检测成功
responseText(),用于取得响应内容
send(),用于发送请求
五,其余跨域技术
1,图像Ping
使用img标签,动态的建立图像,使用onload和onerror事件处理程序来肯定是否接收到了响应
图形Ping是与服务器进行简单,单向,的跨域通讯的一种方式
请求的数据经过查询字符串形式发送的,响应的是任意内容,一般是像素图或204响应
var img = new Image();
img.onload = img.onerror = function(){};
img.src = "http://www.example.com/test?name=Nicholas";
请求从设置src属性那一刻开始,请求中发送了name参数
图像Ping用于跟踪用户点击页面或动态广告曝光次数,
两个缺点,只能发送get请求,没法访问服务器的响应文本,只能单向通讯
2,JSONP
被包含在函数调用中的JSON,
callback({"name":"Nicholas"});
JSONP包含两部分,回调函数和数据,回调函数是当响应到来时应该在页面中调用的函数,函数名通常在请求中指定
数据就是传人回调函数中的JSON数据,例如:http://freegeoip.net/json/?callback=handleResponse,指定的函数名为handleResponse()
JSONP是经过动态script元素使用的,使用时能够为src属性指定一个跨域URL
function handleResponse(response){
alert("you're at IP address" + resopnse.ip + ",which is in" + response.city + "," + response.region_name);
}
var script = document.createElement(script);
script.src="http://freegeoip.net/json/?callback=handleResponse";
document.body.insertBefore(script,document.body.firstChild);
能够直接访问响应文本,支持在浏览器与服务器之间双向通讯,但不能保证安全,肯定JSONP请求是否失败不是很容易
html5给script提供onerror事件处理程序,还没有获得任何任何浏览器支持,为此常经过设置计时器检测指定时间内是否收到了响应
3,Comet
Ajax是一种从页面向服务器请求数据的技术,Comet是一种服务器向页面推送数据的技术
Comet可以让信息近乎实时的被推送到页面上,很是适合处理体育比赛的分数和股票报价
两种实现Comet的方式:长轮询和流
长轮询:页面发起一个到服务器的请求,而后服务器一直保持链接打开,直到有数据可发送,
发送完数据以后,浏览器关闭链接,随即又发起一个到服务器的新请求,这一过程在页面打开期间持续不断
长轮询是服务器等待发送响应后发送数据
HTTP流:浏览器向服务器发送一个请求,服务器保持链接打开,而后周期性向浏览器发送数据
DOM浏览器中,经过监听readystatechange事件及检测readyState的值是否为3,利用XHR对象实现流
function createStreamingClient(url,progress,finished){ var xhr = new XMLHttpRequest(),received = 0; xhr.open("get",url,true); xhr.onreadystatechange = function(){ var result; if(xhr.readyState == 3){ //只取得最新数据并整理计数器 result = xhr.responseText.substring(received); received += result.length; //调用progress回调函数 progress(result); }else if(xhr.readyState == 4){ finished(xhr.responseText); } }; xhr.send(null); return xhr; } var client = createStreamingClient("streaming.php",function(data){ alert("Received:" + data);},function(data){ alert("Done!"); });
4,服务器发送事件1)SSE API 建立到服务器的单向链接,服务器经过这个链接能够发送任意数量的数据, 服务器响应的MIME类型必须是text/event-stream,支持长短轮询,和http流 首先建立一个新的EventSource对象,并传进一个入口点: var source = new EventSource("Myevent.php");url要与建立对象的页面同域 EventSource实例有个readyState属性,0表示正链接到服务器,1表示打开了链接,2表示关闭了链接 还有open事件,在创建链接时触发,message事件,在服务器接收到新事件时触发,error事件,在没法创建链接时触发 服务器发回的数据以字符串形式保存在event.data中 默认状况下,EventSource对象会保持与服务器的活动链接,链接断开会从新链接 强制断开使用close()方法,source.close()2)事件流 服务器事件会经过一个持久的http响应发送,这个响应的MIME类型为text/event-stream 响应的格式为纯文本,最简单的状况是每一个数据项前有data 对于多个连续的以data开头的数据行,将做为多段数据解析,每一个值之间有一个换行分隔符 只有包含data:的数据行后有空行,才会触发messge事件, 经过id:前缀能够给特定的事件指定一个关联的ID,位于data:行前面和后面皆可 设置了ID,EventSource对象会跟踪上一次触发的事件,链接断开时,会向服务器发送一个包含名为last-Event-ID的特殊HTTP头部的请求,以便服务器知道 下一次触发的事件5,Web Socket 在一个单独的持久的链接上提供全双工,双向通讯 一个http请求发送到服务器已发起链接,取得服务器响应后,创建的链接使用http升级从http协议交换为web Socket协议 ws://;wss:// 1)Web Socket API 首先实例一个WebSocket对象并传人要链接的URL var socket = new WebSocket("ws://www.example.com/sever.php"); 必须给websocket构造函数传人绝对的URL, 浏览器在实例化websocket对象后,立刻尝试建立链接,readyState属性 WebSocket.OPENING(0):正在创建链接 WebSocket.OPEN(1):已经创建链接 WebSocket.CLOSING(2):正在关闭链接 WebSocket.CLOSE(3):已经关闭链接 没有readystatechange事件,readyState永远是从0开始的 关闭WebSocket,使用close方法 2)发送和接收数据 send()方法 var socke = new WebSocket("ws://www.example.com/server.php"); socket.send("hello world"); websocket只能发送纯文本数据,对于复杂的结构,将数据序列化为JSON字符串,使用stringify()方法 当服务器向客户端发来消息时,WebSocket对象会触发message事件,这个message事件与其余传递消息的协议相似, 也是把返回的数据保存在event.data属性中 socket.onmessage = function(event){ var data = event.data; //处理数据 } 3)其余事件 open:在成功创建链接时触发 error:在发生错误时触发,链接不能持续 close:在链接关闭时触发 WebSocket对象不支持DOM2级事件监听器,必须使用DOM0级语法分别定义每一个事件处理程序 var socket = new WebSocket("ws://www.example.com/server.php"); socket.onopen = function(){}; socket.onerror = function(){}; socket.onclose = function(){}; 只有close事件对象包含额外的三个属性 wasClean:布尔值,表示链接是否已经明确的关闭 code:服务器返回的数据状态码 reason:字符串包含服务器发回的消息6,SSE与Web Socket SSE,支持单向的从服务器读取数据 WebSocket,支持双向通讯 SEE和XHR组合也能够实现双向通讯六,安全 确保XHR访问的URl安全,通行的作法是验证发送请求者是否有权限访问相应的资源 要求以SSL链接来访问能够经过XHR请求的资源 要求每一次请求都附带通过相应算法计算获得的验证码 要求发送POST而不是GET请求(对CSRF攻击没有做用) 检查来源URL以确保是否可信,(对CSRF攻击没有做用,来源记录很容易伪造) 基于cookie信息进行验证(对CSRF攻击没有做用,容易被伪造)