同源策略产生和如何跨域请求

浏览器同源策略

含义

所谓同源策略,指的是浏览器对不同源的脚本或者文本的访问方式进行的限制。比如源a的js不能读取或设置引入的源b的元素属性。
那么先定义下什么是同源,所谓同源,就是指两个页面具有相同的协议,主机(也常说域名),端口,三个要素缺一不可。

同源是指

* 协议相同
* 域名相同
* 端口相同

目的

同源策略的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。浏览器同时访问2个跨域网站,如果A可以访问B网站的信息,那么就数据随时会被别人窃取。

限制范围

随着互联网的发展,"同源政策"越来越严格。目前,如果非同源,共有三种行为受到限制。

* Cookie、LocalStorage和IndexDB无法读取。
* DOM 无法获取。
* AJAX 请求不能发送。

跨域的几种解决方法

Cookie

Cookie 是服务器写入浏览器的一小段信息,只有同源的网页才能共享。但是,两个网页一级域名相同,只是二级域名不同,浏览器允许通过设置document.domain共享 Cookie。

举例来说,A网页是http://w1.example.com/a.html,B网页是http://w2.example.com/b.html,那么只要设置相同的document.domain,两个网页就可以共享Cookie。

document.domain = 'example.com';

现在,A网页通过脚本设置一个Cookie。

document.cookie = "test1=hello";

B网页就可以读到这个 Cookie。

var allCookie = document.cookie;

注意,这种方法只适用于 Cookie 和 iframe 窗口,LocalStorage 和 IndexDB 无法通过这种方法,规避同源政策,而要使用其他方法规避。

也可以通过后台服务器端设置Cookie的时候,指定Cookie的所属域名为一级域名,比如.example.com

Set-Cookie: key=value; domain=.example.com; path=/

iframe

通过下面2个方法,去获取不同源的iframe里面的DOM或者iframe里面获取外面的DOM,都会跨域

document.getElementById("myIFrame").contentWindow.document
window.parent.document.body

解决方法和Cookie一样,如果两个窗口一级域名相同,只是二级域名不同,那么设置上一节介绍的document.domain属性,就可以规避同源政策,拿到DOM。

这3种方法在这里就不过多描叙了,就是通过url的hash值和iframe里面通信

* 片段识别符(fragment identifier)
* window.name
* 跨文档通信API(Cross-document messaging)

JSONP

它的基本思想是,网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。

首先,网页动态插入<script>元素,由它向跨源网址发出请求。

function addScriptTag(src) {
  var script = document.createElement('script');
  script.setAttribute("type","text/javascript");
  script.src = src;
  document.body.appendChild(script);
}

window.onload = function () {
  addScriptTag('http://example.com/ip?callback=foo');
}

function foo(data) {
  console.log('Your public IP address is: ' + data.ip);
};

上面代码通过动态添加<script>元素,向服务器example.com发出请求。注意,该请求的查询字符串有一个callback参数,用来指定回调函数的名字,这对于JSOPNP是必需的。

服务器收到这个请求以后,会将数据放在回调函数的参数位置返回。

foo({
  "ip": "8.8.8.8"
});

由于<script>元素请求的脚本,直接作为代码运行。这时,只要浏览器定义了foo函数,该函数就会立即调用。作为参数的JSON数据被视为JavaScript对象,而不是字符串,因此避免了使用JSON.parse的步骤。

WebSocket

WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容