第一部分:同源策略:same-origin policy
1.同源策略的由来:
1995年,同源策略由Netscape(曾经的浏览器霸主,拒绝微软收购请求,被IE给整垮。现在发展为火狐浏览器背后的Mozilla)引入。目前,所有浏览器都遵循同源策略。
2.同源定义:即同协议、同域名、同端口号
例如:http://www.test.com:80/test.html; 协议:http;域名:www.test.com;端口号:80(默认端口,可以省略)
http://www.test.com/test100.html (同源) http://test.com/test100.html (不同源,域名不同) http://x.www.test.com/test100.html (不同源,域名不同) http://www.test.com:81/test100.html (不同源,端口号不同) https://www.test.com/test100.html (不同源,协议不同)
但是在IE浏览器上端口号不同被认为是同源
截图自MDN,链接
3.同源策略目的:
防止其它网站恶意窃取数据。 例如: 假设没有同源策略:用户在银行网站A上访问,cookie记录了A银行存款金额、存款频率、存款频率等信息;当用户离开A网站,访问游戏网站B时,此时网站B可以读取cookie。那么用户的隐私就被泄露了! 更严重的是,cookie往往保存用户登录状态,如果用户离开A网站(但是没有退出登录),那么B网站其实是可以冒充用户进入A网站
4.非同源带来的结果:
第二部分:跨域解决方法
1.设置document.domain来跨子域:(适用于cookie、iframe)
比如http://a.test.com和http://b.test.com;
如果设置了document.domain='test.com';那么两者之间可以共享cookie(即一级域名相同,二级域名不同,可以设置document.domain来共享cookie)
同时,服务器可以在设置cookie的时候,指定一级域名,也能达到共享cookie的效果。如:Set-Cookie:key=value;domain=.test.com;path=/
iframe:也可以通过上述document.cookie设置,从而共享cookie、iframe拿到父窗口的DOM、父窗口拿到iframe的DOM。
如:父窗口是http://a.test.com,iframe是http://test.com;当设置了document.domain="test.com"时,就能进行跨域了。
2.同源域名下架设代理服务器:JavaScript将请求发送到代理服务器,代理服务器再将结果返回。
如:'/proxy?url=http://www.test.com'
不过这种显然需要配置额外服务器,开销变大。
3.使用window.name来跨域:
window.name:在不同的页面(甚至不同的域名)加载后依然存在(如果值没被修改,则不会发生变化),并且name值可达2MB(对于一般的运用完全够用)
4.片段识别符(fragment identifier):URL中#后面的部分。比如http://www.test.com#apple的#apple就是片段识别符。
改变片段识别符,页面不会重新刷新
父窗口将信息,写入子窗口片段识别符;子窗口通过监听hashchange事件得到通知
5.window.postMessage:HTML5为了解决跨域问题,引进的全新API:跨文档通信API(cross-document messaging)
父窗口:http://a.com,子窗口:http://b.com;显然两者不同源,但是通过postMessage两者可以实现跨域通信
1 var a=window.open('http://b.com');
2 //父窗口向子窗口发送信息hello 1
3 a.postMessage('hello 1','http://b.com');
4 //子窗口向父窗口发送信息hello 2
5 window.opener.postMessage('hello 2','http://a.com');
6
7 //父窗口和子窗口都能通过message事件,监听对方信息
8 window.addEventListener('message',function(e){
9 console.log(e.data);
10 })
6.JSONP:这个就很常见了。老式浏览器都支持,兼容性好,简单实用。(不过只支持get请求)
基本思想:网页通过添加一个<script>元素,向服务器发送JSON数据,这种方法是不受同源策略限制的;服务器收到请求后,将数据放入指定的回调函数中返回。
截图至阮一峰JavaScript标准参考教程。
添加<script>元素,向服务器发送请求,同时请求中指明了回调函数foo,服务器以回调函数的形式返回数据。
7.websocket:这个是通信协议,好比是打电话。与传统的http协议,只能客户端向服务器发送请求,服务器进行效应的原理不同。
websocket可以由客户端向服务器发送连接请求,也可以服务器向客户端发送连接请求。它们之间的连接是持续打开的数据通道,就好比是打电话!
而websocket不受同源策略制约,可以用来跨域通信。将可以通信的域名放在白名单里。
8.安装flash插件,现在flash插件用的越来越少,而且复杂。不推荐!
9.CORS(跨域资源共享):cross-origin resource sharing(支持所有类型的请求,对比JSONP只支持get请求)
它是一个W3C标准,允许浏览器跨域发送XMLHttpResuest对象。这是Ajax跨域的终极解决方法。
目前,IE10以上,现代浏览器均支持CORS。
主要原理:浏览器发现Ajax跨域请求,就会自动添加一些头部信息;对于非简单请求,还会多出一次附加请求;但是这些用户都察觉不到。而服务器端布置了CORS接口(设置了相关数据信息如:Access-Control-Allow-Origin)
所以:CORS需要客户端与服务器同时支持!
更多详细参考:阮一峰JavaScript标准参考教程
10.可参见:PHP Ajax 跨域问题最佳解决方案
通过设置Access-Control-Allow-Origin来实现跨域。