同源策略是什么

同源政策在1995年由Netscape公司引入浏览器。

最初它的含义是指,A网页设置的Cookie,B网页不能打开,除非这两个网页“同源”。

所谓同源是指:协议相同、域名相同、端口相同

同源策略的目的

同源政策的目的是为了保证用户的信息安全,防止恶意的网站窃取数据。

如果没有同源策略,就会有一下情形:

  1. 首先小明登录网站A(可能是银行、商城等);
  2. 接着小明浏览了攻击者网站B的网页,网页中的脚本读取了网站A的Cookie;
  3. 攻击者获取到网站A的Cookie后,很显然,如果 Cookie 包含隐私(比如存款总额),这些信息就会泄漏。更可怕的是,Cookie 往往用来保存用户的登录状态,如果用户没有退出登录,其他网站就可以冒充用户,为所欲为。

由此可见,"同源政策"是必需的,否则 Cookie 可以共享,互联网就毫无安全可言了。

因为浏览器同时还规定,提交表单不受同源政策的限制。

同源策略的发展

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

  • Cookie、LocalStorage和IndexDB无法读取(Cookie是服务器写入浏览器的一小段信息,只有同源的网页才能共享。但是,两个网页一级域名相同,只是二级域名不同,浏览器允许通过document.domain共享Cookie。在www.example.com中,一级域名是example.com,而二级域名是www.example.com。二级域名代表的就是一级域名下的一台主机。);
  • DOM无法获得(同样要求一级域名相同)
  • AJAX请求不能发送
跨域的需求

在前后端分离的趋势下,A网站下的页面有时候也需要访问B网站的一些数据,所以得想办法绕过同源策略,来跨域交换数据。

跨域的做法如下:

JSONP

JSONP的原理是:script标签可以加载其他域下的js文件。我们可以利用这个特性实现从其他域下获取数据。

比方说我们想查询第三方的商城网站的商品信息,我们可以通过script标签发起一个请求:

<script src="http://shop/getProductions?type=0&pageIndex=1&pageSize=10"></script>


后端接收到请求后,查询商品信息,然后将查询结果放到一份js文件里,传给前端,比如:

onProductionsReceived([
{id:0, name:'商品1', price: 16},
{id:1, name:'商品2', price: 52},
{id:2, name:'商品3', price: 32},
]);


前端浏览器收到后,会执行该js文件,也就是执行了onProductionsReceived()函数。这里需要注意的是,onProductionsReceived()函数需要事先在前端定义好,比如:

function onProductionsReceived(productions) {
console.log("收到了商品列表", productions);
}


CORS

CORS的全称是Cross-Origin Resouece Sharing(跨域资源共享),是一种ajax跨域请求资源的方式,支持现代浏览器,IE支持到10以上。

CORS的原理为:

  1. 浏览器发现该请求不符合同源策略,给请求加上一个请求头Origin;
  2. 服务器收到后,会在响应中加入一个响应头Access-Control-Allow-Origin;
  3. 浏览器拿到响应后,判断Access-Control-Allow-Origin中是否包含指定Origin,如果是,则处理响应,否则驳回响应;
res.setHeader('Access-Control-Allow-Origin','http://localhost:8080')//允许http://localhost:8080的请求
res.setHeader('Access-Control-Allow-Origin','*') //允许所有的请求


注意,同源策略并不限制请求的发起和响应,只是浏览器拒绝了js对响应资源的操作。

代理

我们在开发前端项目的时候,经常会需要在开发环境通过ajax访问远程服务器上的数据,这时候就会遇到跨域问题,导致数据不能正常获取。这时用CORS可能比较不恰当,因为需要服务器端允许http://127.0.0.1:8080这个域。那么我们就可以使用代理的方式来访问访问跨域数据。

代理的原理是:同源策略只是对浏览器的限制,对服务器没有限制。具体为:

  1. 浏览器向开发环境服务器发起请求;
  2. 开发环境服务器根据url向目标远程服务器发起请求,收到数据后发给浏览器;
  3. 浏览器收到数据后显示;