同源策略 & 跨域

同源策略

浏览器出于安全方面的考虑,只允许与本域下的接口交互。不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源。这是浏览器的安全策略。

“同源”指的是“三个相同”:

  • 协议相同:如都是 http 或 https
  • 域名相同:如都是 http://www.abc.com/a 和 http://www.abc.com/b
  • 端口相同:如都是80端口

注意的一点:对于当前页面来说页面存放的JS文件的域不重要,重要的是加载该JS页面所在的域。

如果非同源,共有三种行为受到限制:

1) 无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB。

2) 无法接触非同源网页的 DOM。

3) 无法向非同源地址发送 AJAX 请求(可以发送,但浏览器会拒绝接受响应)。

举个例子,假如你登陆了一个电商网站,电商网站给你设置了一些cookie,这些cookie一般包含了你的个人信息及隐私,当你离开了电商网站再去浏览其他网站,倘若没有同源策略,那么其他网站可以读取你的cookie并且获得了你的资料,还可以进行修改,这是一个非常危险且恐怖的事情!这不仅是个人隐私的泄露,可能会对用户造成其他影响。

跨域

浏览器向不同源的网站请求资源,都可以说是跨域。

因为同源政策,我们请求不同源的地址的资源会受到很多影响,接下来说下如何合理规避上面的限制。

1.  JSONP(JSON with padding)

JSONP 是通过 script 标签加载数据的方式去获取数据当做 JS 代码来执行,前提在页面上声明一个函数,函数名通过接口传参的方式传给后台,后台解析到函数名后在原始数据上“包裹”这个函数名,发送给前端。换句话说,JSONP需要对应接口的后端的配合才能实现。

HTML 中 script 标签可以加载其他域下的js,例如:

<script src="http://api.jirengu.com/weather.php"></script>

我们向这个天气接口获取数据,但是有个问题是返回来的格式是JSON的数据,我们没法操作和使用,这时我们可以做

<script src="http://api.jirengu.com/weather.phpcallback=showData?"></script>

这个请求到达后端后,后端回去解析callback这个参数获取到字符串showDate,在发送数据做如下处理:
之前后端返回数据:{"city":hangzhou","weather":"晴天"} 现在后端返回数据: showDate({"city":"hangzhou","weather":"晴天"}) 前端script 标签在加载数据后会把 “showDate({"city":"hangzhou","weather":"晴天"}) ”做为 JS 来执行,这实际上就是调用 showDate 这个函数,同事参数是 {"city":"hangzhou","weather":"晴天"} 。 用户只需要在加载提前在页面定义好 showDate 这个全局函数,在函数内部处理参数即可。

<script>
function showData(ret){
console.log(ret)
}
</script>
<script src="http://api.jirengu.com/weather.php?callback=showData"></script>

2.CORS

CORS 全称是跨域资源共享(Cross-origin Resource Sharing) ,是一种 ajax 跨域请求资源的方式,支持现代浏览器, IE支持10以上。实现方式很简单,当你使用 XMLHttpRequest 发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin,后台进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头: Access-Control-Allow-Origin;浏览器判断该响应头中是否包含 Origin 的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。所以 CORS 的表象是让你觉得它与同源的 ajax请求没啥区别,代码完全一样。

关于CORS通信,整个过程是由浏览器完成的,所以对于前端来说,只要发送 ajax 请求就可以了,对于服务器端则要实现响应的CORS接口,就可以跨域通信。

3.降域

iframe元素可以在当前网页之中,嵌入其他网页。每个iframe元素形成自己的窗口,即有自己的window对象。iframe窗口之中的脚本,可以获得父窗口和子窗口。但是,只有在同源的情况下,父窗口和子窗口才能通信;如果跨域,就无法拿到对方的 DOM。

如果想要获取不同源的其他窗口的通信,可以将两个网页设置 document.domain属性 ,将两个网页降到同一个域名下。

4.postMessage

这个 API 为window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源,这个方法可以安全的实现跨域通信。

window.frames[0].postMessage(this.value,'*')

 在需要访问数据的网页中用来监听postMessage。

原文地址:https://www.cnblogs.com/ianyanyzx/p/9743950.html