一,同源
1>基本内容,目的
同源策略是两个页面协议,域名,端口号相同,同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。
2>非同源,共有三种行为受到限制
(1)cookie、LocalStorage 和 IndexDB 无法读取。
只有两个网址域名和端口相同就可以共享cookie,也就是说http://example.com设置的Cookie,可以被https://example.com读取。
(2)DOM 无法获得。(如果两个网页不同源,就无法拿到对方的DOM。典型的例子是iframe窗口和window.open方法打开的窗口,它们与父窗口无法通信。)
(3)AJAX 请求不能发送。
3>解决方法
1)document.domain:这种方法只适用cookie和iframe 窗口.
由于安全限制,domain不是可以设置任何值的,我们只能把domain设置成自身或者更高一级的父域,且主域必须相同
两个网页一级域名相同,只是二级域名不同,浏览器允许通过设置document.domain共享 cookie。
如果两个窗口一级域名相同,只是二级域名不同,设置document.domain属性,就可以规避同源政策,拿到DOM。
场景一:http://www.example.com/a.html中有一个iframe,它的src是http://www.example.com/b.html
显示时不同域不能用js获取iframe中的东西
//http://www.example.com/a.html
<iframe src="http://example.com/b.html" id="iframe"></iframe>
document.domain="example.com";
function text(){
alert(document.getElementById("iframe").contentWindow)
}
//http://www.example.com/b.html
document.domain="example.com";
场景二:ajax的方法去与不同子域的页面交互(document.domain+iframe(隐藏))
原理:让这个iframe载入一个与你想要通过ajax获取数据的目标页面处在相同的域的页面,所以这个iframe可以和这个ajax正常去获取数据,然后是通过上面的document.domain方法
3)解决跨域窗口的通信问题:
1》location.hash片段识别符:URL的#号后面的部分,
1.1》原理:hash变化不会导致页面刷新,所以利用hash传值,创建定时器,坚持hash变化,执行相应操作
1.2》优点:解决域名完全不相同的,并且实现双向通讯
1.3》缺点:安全问题,location.hash会直接暴露url里;由于url大小限制,支持传递的数据量不大;有些浏览器会在hash变化时产生历史记录,因此可能影响用户体验
1.4》场景:假设github.io域下a.html和shaonian.eu域下b.html存在跨域请求
1)a.html页面创建一个隐藏的iframe,src指向b.html,其中src中可以通过hash传值给b.html
2)b.html页面处理完传入的hash后通过修改a.html的hash值达到将数据传给a.html的目的
(需要引入c.html与a.html同源的页面,a.html通过iframe将数据通过hash传给b.html,b.html通过iframe将数据通过传给c.html,c.html通过设置parent.parent.location.hash设置a.html的hash达到目的)
3)a.html添加一个定时器,每隔一段时间判断自身的location.hash是否改变,以此响应处理
//bao.com/c.html
var timer=setInterval(checkHash,1000);
function checkHash(){
parent.parent.location.hash=self.location.hash.substring(1);
}
//bao.com/a.html
<iframe src="http://www.hui.com/b.html" id="iframe"></iframe>
<input type="button" onClick="changeColor()" id="btn"/>
var iframe=document.getElementById("iframe");
var timer=setInterval(checkHash,1000);
function checkHash(){
switch(location.hash){
case:"#mainred":
document.getElementById("btn");
break;
}
}
function changeColor(){
iframe.src="http://www.hui.com/b.html#red"
}
//hui.com/b.html
<iframe src="http://www.bao.com/c.html" id="iframe" style="none"></iframe>
var timer=setInterval(checkHash,1000);
function checkHash(){
switch(location.hash){
case:"#red":
callback();
break;
}
}
function callback(){
document.getElementById("iframe").style.color="red"
}
2》window.name:它的name属性有个特征,在一个窗口的生命周期内,窗口载入的所有页面都共享一个window.name,每个窗口对window.name都有读写的权限,window.name是持久存在在一个窗口载入过的所有页面中,并不会因为新页面的载入而进行重置。并且可以支持非常长的name值(2MB)
场景:www.examole.com/a.html页面通过js获取不同域www.cnvlogs.com/data.html里的数据
在data.html中给当前的window.name设置a.html需要的数据,在a.html中使用隐藏的iframe充当中间人的角色,有iframe获取data.html的数据,然后a.html再去得到iframe获取到的数据
//a.html
<iframe src="http://www.cnblogs.com/data.html" style="display:none"></iframe>
<script>
var iframe=document.getElementById("iframe");
iframe.onload=function(){
var data=iframe.contentWindow.name;
}
</script>
//www.cnblogs.com/data.html
window.name="我是a.html想要的数据";
3》PostMessage API:跨域交换数据
解决LocalStorage 和 IndexDB,HTML5允许跨窗口通信,不论这两个窗口是否同源
不能和服务器交换数据,只能在两个窗口之间交换数据
otherWindow.postMessage(message,targetOrigin,[transfer]);
4)AJAX有三种方法规避这个限制:
1》JSONP:
最大特点:就是简单适用,老式浏览器都支持,服务器改造非常小
基本思想是,网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
缺点:只能使用git请求
var jsonpCallback=function(data){
alert("查询结果:firstName"+data.firstName);
}
var url="http://127.0.0.1:3000/?callback=jsonpCallback";
var script=document.createElement('script');
script.setAttribute('scr',url);
document.getElementsByTagName('head')[0].appendChild(script);
2》WebSocket
WebSocket是一种基于TCP的新的网络协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。有一个字段是Origin,表示该请求的请求源(origin),正是因为有了Origin这个字段,所以WebSocket才没有实行同源政策。浏览器发出的WebSocket请求的头信息Sec-WebSocket-Key,Sec-WebSocket-Protocol等。
3》CORS
CORS是跨源资源共享(Cross-Origin Resource Sharing)的缩写。它是W3C标准,是跨源AJAX请求的根本解决方法。CORS允许任何类型的请求。
4>jsonp和cors区别
a、 JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。
b、 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。
c、 JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS。
二.跨域资源共享(CORS)
1>原理
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制,需要服务器和浏览器共同支持,但是目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。所以实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
2>为什么要验证
基于CSRF(跨站请求伪造)的风险,各主流浏览器会对动态的跨域请求进行特殊的验证处理,验证处理分为简单请求验证处理和预先请求验证处理。
2>触发简单请求与预先请求的条件
只要同时满足以下两大条件,就属于简单请求,凡是不同时满足两个条件,就属于预先请求。
1)请求方法是以下三种方法之一:GET,POST,HEAD
2)HTTP的头信息不超出以下几种字段:Accept,Accept-Language,Content-Language,Last-Event-ID,
Content-Type(只限于三个值application/x-www-form-urlencoded multipart/form-data、text/plain)
3>简单请求
浏览器直接发出CORS请求,它会在头信息之中,增加一个Origin字段(表示请求来自哪个源),表明这是一个跨域请求。
服务器接收到请求后,根据自己的跨域规则,决定是否同意这次请求。
如果Origin指定的域名在许可范围内,服务器返回的响应会在头信息里多几个字段,来返回验证结果,如果验证成功会直接返回访问的资源内容。
如果Origin指定的源不在许可范围内,服务器会返回一个正常的HTTP回应,但是回应的头信息没有包含Access-Control-Allow-Origin字段,浏览器就知道出错了,从而抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。(返回403状态码:服务器理解客户端的请求,但是拒绝执行此任务)
Access-Control-Allow-Origin:该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。
Access-Control-Allow-Credentials:该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。
Access-Control-Expose-Headers:该字段可选。CORS请求时想非基本字段,就必须在Access-Control-Expose-Headers里面指定
4>预先请求
是在正式通信之前,增加一次HTTP查询请求,就是"预检"请求。
"预检"请求用的请求方法是OPTIONS是用来询问的要被跨域访问的服务器,是否允许当前域名下的页面发送跨域请求。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。(403错误)
头信息里面关键字段是Origin(表示请求来自哪个源)。服务器收到"预检"请求以后,检查了Origin、Access-Control-Request-Method(该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法)和Access-Control-Request-Headers(该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段)字段以后,确认允许跨源请求,就可以做出回应。