同源策略和跨域解决方法

第一部分:同源策略: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.非同源带来的结果:

  • cookie,localStorage和indexdDB无法读取
  • DOM无法获得
  • Ajax请求无效(请求发送后,浏览器不会进行响应)

 

第二部分:跨域解决方法

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来实现跨域。

 

更多参考:1.阮一峰JavaScript标准参考教程

2.Ajax廖雪峰的官方网站

3.js中几种常见的跨域方法原理详解

 

posted @ 2017-12-14 16:21  why_not_try  阅读(402)  评论(0编辑  收藏  举报