前言
通过XHR实现ajax通信的一个主要限制是 跨域安全策略。XHR对象只能访问与包含他的页面位于同一个域的资源。当发起一个资源请求的时候,请求头会带有一个 Origin头部,响应头会带有一个Access-Origin-Allow-Origin,如下:
Origin:http://www.test.com
Access--Control-Allow-Origin: http://www.test.com // Access--Control-Allow-Origin: * // 代表公共资源
如果这个头部和Origin头部不相符合的时候,浏览器会驳回请求。于是就出现了跨域请求技术,下面是几种方式的总结.
实现一:跨浏览器的CORS
1 function createCORSRequest(method,url) { 2 var xhr = new XMLHttpRequest(); 3 if ("withCredentials" in xhr){ 4 xhr.open(method,url,true); 5 }else if(typeof XDomainRequest!== "undifined"){ 6 xhr=new XDomainRequest(); 7 xhr.open(method,url); 8 }else{ 9 xhr=null; 10 } 11 return xhr; 12 } 13 14 var request=createCORSRequest('get','http://www.test.com'); 15 if(request){ 16 request.onload=function(){ 17 // onreadystatechange检测成功 18 // 处理 requset.responseText 19 } 20 request.onerror=function(){ 21 // 处理请求失败 22 } 23 requset.send(null); 24 }
上面是跨浏览器的实现方式,下面分析一下:
IE对CORS的实现
IE8中引入了XDR(XDomainRequest)类型,此类型和XMLHttpResquest相似,但是可以实现安全的跨域通信。
不同之处:
① 不能通过setRequestHeader()设置自定义头部,只能设置请求头部信息的Content-Type字段, xhr.contentType
② 不能访问响应头信息,即调用getAllResponseHeaders()总是返回空字符串
③ 不能发送和接受cookie
XDR对象的方法
① open() 只接受两个参数,所有XDR请求都是异步的
② send() 同XHR对象一样
其他事件
1 var xdr=new XDomainRequest(); 2 xdr.onload=function(){ 3 // xdr.responseText 响应的原始文本 4 // 无法确定 响应的状态代码,即无 xhr.readyState和xhr.status 5 } 6 xdr.onerror=function(){ 7 alert("An error occurred."); 8 } 9 xdr.open('get',"url"); 10 xdr.send(null);
其他浏览器对CORS的实现
FireFox3.5+,Safari4+,Chrome等等都实现了原生CORS的支持。但是默认情况下,跨域请求不提供凭据,可以设置withCredentials表示带凭据的请求
于是,设置跨浏览器的CORS的时候,可以先检测是否带 withCredentials 属性,若无,再检测是否存在XDomainRequest对象。
实现二: 图像Ping
可行性:网页可以从任何网页中加载图像,不用担心跨域问题。
具体实现:利用 img 标签,动态创建图像。
1 var img=new Image(); 2 img.onload=img.onerror=function(){ 3 alert("done"); 4 } 5 img.src="http://www.example.com/test?name=Kasmine";
这里创建了一个Image实例,通过 img.src 向服务器发起GET请求(参数为name),服务器收到请求后,通过对请求url的解析,判断请求内容。
应用:图像Ping主要用于用户点击页面或者浏览量的统计。
缺点:只有get请求,不能访问服务器的响应文本
实现三: JSONP
jsonp :“JSON with padding”顾名思义就是 包含在函数回调的json数据。具体实例如下:
1 function handleResponse(response) { 2 // 处理 response 3 } 4 var script=document.createElement("script"); 5 script.src='http://www.example.com?callback=handleResponse'; 6 document.body.insertBefore(script,document.body.firstChild);
<script>标签和<img>标签一样,不受访问域的限制。首先我们创建一个 script 元素,插入到页面后立刻执行。客户端定义了一个名为handleResponse的回调函数,向 http://www.example.com 发起GET请求,服务器端进行响应:
callback({"name":"Nicholes"});
客户端在响应到来时,会调用 回调函数 handleResponse
实现四:修改document.domain跨子域
两个域名必须属于同一个基础域名
实现五:通过使用HTML5的window.postMessage方法来传送数据
【始终使用origin和source属性验证发件人的身份】
1 窗口A: 2 window.postMessage(msg,urlOfB); 3 窗口B: 4 window.onmessage(event){ 5 var data=event.data; 6 var origin=event.origin; 7 }
小结
同源策略是XHR的一个约束,他要求“相同的域,相同的端口,相同的协议”才能进行通信。于是就出现了跨域访问的技术。
实现 跨域还有其他的方法,在这里就不多说了,日后学习到了,再继续补上~