同源是指,域名,协议,端口号均相同,如图:javascript
注意:localhost和127.0.0.1虽然都指向本机,但也是跨域.
浏览器同源策略(same-origin policy).简单的讲,同源策略就是浏览器为了保证用户安全,防止恶意的网站盗取数据,禁止不一样域之间的JS进行交互.会限制以下行为:css
CORS是跨域资源共享(Crocss-Origin Resource Sharing)的缩写.是W3C标准.跨域资源共享机制容许Web应用服务器进行跨域访问控制,从而使跨域传输得以安全进行.对于这个方式阮一峰老师有一篇文章专门讲这个的,跨域资源共享CORS详解可供参考.还有就是MDN里有关于HTTP访问控制的文档.HTTP访问控制CORShtml
简单的说就是:前端
请求方在头信息中多一个Origin字段来讲明本次请求来自哪一个源.(协议+域名+端口)
服务器响应头信息中会多几个字段java
该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求.git
该字段可选。它的值是一个布尔值,表示是否容许发送Cookie。默认状况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie能够包含在请求中,一块儿发给服务器。这个值也只能设为true,若是服务器不要浏览器发送Cookie,删除该字段便可.github
该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。若是想拿到其余字段,就必须在Access-Control-Expose-Headers里面指定。上面的例子指定,getResponseHeader('FooBar')能够返回FooBar字段的值。web
开发者须要在AJAX中设置withCredentials属性为true.
JSONP是JSON with Padding的简称.这是一种利用浏览器漏洞解决跨域的办法.HTML脚本元素能够不受浏览器同源策略的限制。即咱们请求HTML、CSS、JS文件时浏览器不会作限制。因此运用这个特色,经过加载外部js文件的方式来向其余资源发出http请求。正是由于是请求文件,因此JOSNP只能GET,不能POST.简单来讲,JSONP方案就是页面动态建立一个script标签.chrome
<script src="www.baidu.com/data.js?callback=Callback">
而后服务端根据咱们传过去的参数,进行处理.json
举个例子:
callBackFunc = function(data){ console.log(data); }; var script = document.createElenent('script'); script.type = "text/javascript"; script.src = "http://www.localhost:8888/data.json?callBack= callBackFunc"; document.body.appendChild(script);
JSONP的缺点:
浏览器有跨域限制,可是服务器没有,因此能够由服务器请求所要域的资源再返回给客户端。
服务器可解决一切跨域问题.
window.postMessage() 方法能够安全地实现跨源通讯。一般,对于两个不一样页面的脚本,只有当执行它们的页面位于具备相同的协议(一般为https),端口号(443为https的默认值),以及主机 (两个页面的模数 Document.domain设置为相同的值) 时,这两个脚本才能相互通讯。window.postMessage() 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。
window.postMessage() 方法被调用时,会在全部页面脚本执行完毕以后(e.g., 在该方法以后设置的事件、以前设置的timeout 事件,etc.)向目标窗口派发一个 MessageEvent 消息。 该MessageEvent消息有四个属性须要注意: message 属性表示该message 的类型; data 属性为 window.postMessage 的第一个参数;origin 属性表示调用window.postMessage() 方法时调用页面的当前状态; source 属性记录调用 window.postMessage() 方法的窗口信息。
关于这个的文章可参考window.postMessage
举个例子:
页面和其余打开的新窗口的数据传递
//同域 - a页面 <a href="./b.html" target="_blank">跳转</a> <script> window.addEventListener('message', function(event) { if(event.origin == 'http://hwc.home.com:3000') { //同域与不一样域,都是靠origin判断 console.log(event.data) } }) </script> //b页面 <script> document.getElementById('app').onclick = function() { var target = 'http://hwc.home.com:3000' opener.postMessage('b.html send message', target) } </script>
页面与嵌套的iframe消息
//a页面 <iframe src="http://hwc.home.com:4000/home.html"></iframe> var iframe = document.getElementsByTagName('iframe')[0]; window.onMessage = function(event) { if(event.source == iframe.contentWindow) {} //嵌套iframe除了origin外还能够比较用source } //iframe页面 window.parent.postMessage(data, target) window.addEventListener('message',function(e){ if(e.source!=window.parent) return; //子页面能够经过此方法判断是不是父页面的消息 window.parent.postMessage('data','*'); },false);
多窗口之间消息传递不是指我用浏览器分别打开了两个页面,就能互相通讯了。须要一个otherWindow,一个其余窗口的引用 window.postMessage
语法 ——> otherWindow.postMessage(message, targetOrigin, [transfer]); otherWindow ——> 其余窗口的一个引用,好比iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。 message ——> 将要发送到其余 window的数据 targetOrigin——> 经过窗口的origin属性来指定哪些窗口能接收到消息事件,其值能够是字符串"*"(表示无限制)或者一个URI。
iframe跨域也是利用浏览器中带有src的标签能够跨域访问.凡是拥有src属性的标签都有跨域的能力.例如:<script> ,<img> ,<iframe>.
对于主域相同,子域不一样的状况,能够经过设置document.domain的办法解决.具体的作法是能够在http://www.a.com/a.html
和http://script.a.com/b.html
两个文件中分别加上document.domain = ‘a.com’;而后经过a.html文件中建立一个iframe,去控制iframe的contentDocument,这样两个js文件之间就能够“交互”了。固然这种办法只能解决主域相同而二级域名不一样的状况,若是你异想天开的把script.a.com的domian设为alibaba.com那显然是会报错地!
主域名:就是指一我的经过域名注册商注册的那个名字(domain name),它在注册商的系统中有个惟一的域名ID。例如www.baidu.com,主域名就是baidu.com.而主域名左边的就是他的子域名.
代码以下:
父窗口(http://www.a.com/a.html
)
//<iframe id="iframe" src="http://script.a.com/b.html"></iframe> <script> var iframe = document.createElement('iframe'); iframe.src = 'http://script.a.com/b.html'; iframe.style.display = 'none'; document.body.appendChild('iframe'); //设置domain值. document.domain = 'a.com'; var user = 'admin'; </script>
子窗口(http://script.a.com/b.html
)
<script> document.domain = 'a.com'; // 获取父窗口中变量 console.log('data from parent=> ' + window.parent.user); </script>
这样就能在子窗口获取父窗口里的数据了.
一、安全性,当一个站点(b.a.com)被攻击后,另外一个站点(c.a.com)会引发安全漏洞。
二、若是一个页面中引入多个iframe,要想可以操做全部iframe,必须都得设置相同domain。
对于主域不一样的情形,可用location.hash 和window.name解决.
原理是利用location.hash来进行传值。在url: http://a.com#segmentfault
中的‘#segmentfault’就是location.hash,改变hash并不会致使页面刷新,因此能够利用hash值来进行数据传递,固然数据容量是有限的。假设域名a.com下的文件test1.html要和b.com域名下的test2.html传递信息,test1.html首先建立自动建立一个隐藏的iframe,iframe的src指向b.com域名下的test2.html页面,这时的hash值能够作参数传递用。test2.html响应请求后再将经过修改test1.html的hash值来传递数据(因为两个页面不在同一个域下IE、Chrome不容许修改parent.location.hash的值,因此要借助于a.com域名下的一个代理iframe;Firefox能够修改)。同时在test1.html上加一个定时器,隔一段时间来判断location.hash的值有没有变化,一点有变化则获取获取hash值。
a.com下的test1.html
function startRequest(){ var iframe = document.createElement('iframe'); iframe.style.display = 'none'; iframe.src = 'http://www.b.com/test2.html#paramdo'; document.body.appendChild(iframe); } function checkHash() { try { var data = location.hash ? location.hash.substring(1) : ''; if (console.log) { console.log('Now the data is '+data); } } catch(e) {}; } setInterval(checkHash, 2000);
b.com域名下的test2.html
//模拟一个简单的参数处理操做 switch(location.hash){ case '#paramdo': callBack(); break; case '#paramset': //do something…… break; } function callBack(){ try { parent.location.hash = 'somedata'; } catch (e) { // ie、chrome的安全机制没法修改parent.location.hash, // 因此要利用一个中间的b.com域下的代理iframe var iframeproxy = document.createElement('iframe'); iframeproxy.style.display = 'none'; iframeproxy.src = 'http://a.com/test3.html#somedata'; // 注意该文件在"a.com"域下 document.body.appendChild(iframeproxy); } }
a.com域名下的test3.html
//由于parent.parent和自身属于同一个域,因此能够改变其location.hash的值 parent.parent.location.hash = self.location.hash.substring(1);
缺点,暴露数据在url中.
对于主域不一样的情形,可用location.hash 和window.name解决.
iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操做。
有三个页面:
1) 应用页面建立一个iframe,src指向数据页面.数据页面会把数据附加到这个iframe的window.name上.
b.com/test2.html 代码
<script type="text/javascript"> window.name = 'I was data!'; // 这里是要传输的数据,大小通常为2M,IE和firefox下能够大至32M左右 //数据格式能够自定义,如json、字符串 </script>
2) 在应用页面中监听iframe的onload事件,在事件中设置这个iframe的src指向本地域的代理文件(代理页面和应用页面在同一域下,能够相互通讯.)
a.com/test1.html 代码
<script type="text/javascript"> var state = 0, iframe = document.createElement('iframe'), loadFunction = function() { if (state === 1) { var data = iframe.contentWindow.name; // 读取数据 console.log(data); //打印'I was data!' } else if (state === 0) { state = 1; iframe.contentWindow.location = "http://a.com/proxy.html"; // 设置的代理文件 } }; iframe.src = 'http://b.com/test2.html'; if (iframe.attachEvent) { iframe.attachEvent('onload', loadFunction); } else { iframe.onload = loadFunction; } document.body.appendChild(iframe); </script>
3) 获取数据之后销毁这个iframe,释放内存.这也保证了安全性.(不被其余域iframe 访问)
<script type="text/javascript"> iframe.contentWindow.document.write(''); iframe.contentWindow.close(); document.body.removeChild(iframe); </script>
window.top方法能够访问最顶层的window对象,能够取到最顶层window对象的属性和方法。这样子框架就能够操做父页面的交互了。window.parent能够获得父框架的window对象。
1) a页面代码
<script type="text/javascript"> function funA(){ console.log("a页面的方法"); } iframe = document.createElement('iframe'); iframe.style.display = 'none'; iframe.src = 'http://a.com:8080/b.html'; document.body.appendChild(iframe); </script>
2) b页面的代码
<script type="text/javascript"> console.log(window.top.funA()); function funB(){ console.log("b页面的方法"); } iframe = document.createElement('iframe'); iframe.style.display = 'none'; iframe.src = 'http://a.com:8080/c.html'; document.body.appendChild(iframe); </script>
3) c页面代码
<script type="text/javascript"> console.log(window.parent.funB()); </script>
cookie除了有exprise这个属性以后还有path这个属性,这个属性是用来设置可访问到cookie的路径的,默认的是在当前cookie页面的子目录下是能够访问到的,可是默认的状况下咱们是没法再其余父目录下面访问到这个cookie,这个时候咱们就能够经过设置cookie来实现这个功能
如上面所说,可是在跨域之间的传值要怎样实现呢,其实cookie除了有path,还存在domain,domain这个属性是能够实现跨域的,可是必须保证这两个域名有公共部分,何为公共部分?就是像www.qq.com和www.sport.qq.com 这样都有相同的qq.com的域名,具体的使用方法是把domain设置为相同部分的域名,具体以下:
document.cookie = "name=value;expires=date;path=/;domain=qq.com"
另外在使用cookie的时候咱们还须要注意的是cookie的编码问题,由于在cookie是不支持逗号、空格、分号的,因此在设置cookie的时候,须要使用escape()将输入的信息进行转码,而后在要调用的时候使用unescape()来从新转换回来.
WebSocket对象提供了用于建立和管理 WebSocket 链接,以及能够经过该链接发送和接收数据的 API。
WebSocket构造器方法接受一个必须的参数和一个可选的参数:
WebSocket WebSocket(in DOMString url, in optional DOMString protocols); WebSocket WebSocket(in DOMString url,in optional DOMString[] protocols);
url :表示要链接的URL。这个URL应该为响应WebSocket的地址。
protocoles 能够是一个单个的协议名字字符串或者包含多个协议名字字符串的数组。这些字符串用来表示子协议,这样作可让一个服务器实现多种WebSocket子协议(例如你可能但愿经过制定不一样的协议来处理不一样类型的交互)。若是没有制定这个参数,它会默认设为一个空字符串。(可选)
构造器方法可能抛出如下异常:
SECURITY_ERR 试图链接的端口被屏蔽。
WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通讯,同时容许跨域通信,是server push技术的一种很好的实现。
原生WebSocket API使用起来不太方便,咱们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。具体可参阅前端常见跨域解决方案
H5新接口window.postMessage MDN
HTTP访问控制CORS MDN
跨域资源共享CORS详解
JavaScript跨域总结与解决办法
详解跨域(最全的解决方案)
浅谈几种跨域的方法
H5新接口webSocket MDN