一、浏览器的同源策略
1、什么是浏览器的同源策略
浏览器的同源策略:
js脚本在未经允许的情况下,不能够访问其他域下的内容。
2、同源
同源:
协议,域名,端口都相同的则是同源,其中一个不同则都不属于同源。
3、为什么会有同源策略
简单来说是为了安全。
1.为了防止恶意网页可以获取其他网站的本地数据。
2.为了防止恶意网站iframe其他网站的时候,获取数据。
3.为了防止恶意网站在自已网站有访问其他网站的权利,以免通过cookie免登,拿到数据。
4、同源策略主要限制
同源策略主要限制三个方面:
1.无法读取非同源的 cookie、Storage、indexDB的内容。
2.无法读取非同源的DOM。
3.无法发送非同源的ajax,更加准确的说应该是发送了请求但被浏览器拦截了,也就是说浏览器会拦截非同源的请求。
5、哪些不受同源策略限制
1.页面上的链接,比如 a 链接。
2.重定向。
3.表单提交。
4.跨域资源的引入,比如:script, img, link, iframe。
二、如何解决跨域问题
1.JSONP
JSONP的原理:
JSONP 的原理很简单,就是利用 <script> 标签没有跨域限制的漏洞。通过 <script> 标签指向一个需要访问的地址并提供一个回调函数来接收数据当需要通讯时。
JSONP 的实现:
比如说,客户端这样写
<script src="http://www.smyhvae.com/?data=name&callback=myjsonp"></script>
上面的src中,data=name是get请求的参数,myjsonp是和后台约定好的函数名。 服务器端这样写:
myjsonp({
data: {}
})
于是,本地要求创建一个myjsonp 的全局函数,才能将返回的数据执行出来。
JSONP 使用简单且兼容性不错,但是只限于 get 请求
2.CORS
可以理解为
:同时支持同源和跨域的Ajax
1、CORS需要浏览器和后端同时支持
2、浏览器会自动进行 CORS 通信,实现CORS通信的关键是服务端。只要后端实现了 CORS,就实现了跨域.
3、服务端设置 Access-Control-Allow-Origin 就可以开启 CORS。 该属性表示哪些域名可以访问资源,如果设置通配符则表示所有网站都可以访问资源
header("Access-Control-Allow-Origin: * ");
3.document.domain + iframe跨域
该方式只能用于二级域名相同的情况下,比如
a.test.com
和b.test.com
适用于该方式。
只需要给页面添加document.domain = 'test.com'
表示二级域名都相同就可以实现跨域
1.)父窗口:(http://www.domain.com/a.html)
<iframe id="iframe" src="http://child.domain.com/b.html"></iframe>
<script>
document.domain = 'domain.com';
var user = 'admin';
</script>
2.)子窗口:(http://child.domain.com/b.html)
document.domain = 'domain.com';
// 获取父窗口中变量
alert('get js data from parent ---> ' + window.parent.user);
4.Hash
url 的 #
后面的内容就叫 Hash
。Hash
的改变,页面不会刷新。这就是用 Hash
做跨域通信的基本原理。
补充:url的?后面的内容叫
Search
。Search
的改变,会导致页面刷新,因此不能做跨域通信。
使用举例:
场景: 我的页面 A 通过iframe或frame嵌入了跨域的页面 B。现在,我这个A页面想给B页面发消息,怎么操作呢?
首先,在我的A页面中:
//伪代码
var B = document.getElementsByTagName('iframe');
B.src = B.src + '#' + 'jsonString'; //我们可以把JS 对象,通过 JSON.stringify()方法转成 json字符串,发给 B
然后,在B页面中:
// B中的伪代码
window.onhashchange = function () { //通过onhashchange方法监听,url中的 hash 是否发生变化
var data = window.location.hash;
};
5.postMessage()方法
H5中新增的postMessage()方法,可以用来做跨域通信。既然是H5中新增的,那就一定要提到。
这种方式通常用于获取嵌入页面中的第三方页面数据。一个页面发送消息,另一个页面判断来源并接收消息
// 发送消息端
window.parent.postMessage('message', 'http://B.com');
// 接收消息端
var mc = new MessageChannel();
mc.addEventListener('message', (event) => {
var origin = event.origin || event.originalEvent.origin;
if (origin === 'http://blog.poetries.com') {
console.log('验证通过')
}
});
三、跨域请求到底会不会被服务器执行
请求有的时候会被执行,有的时候不会执行。
什么时候会执行,什么时候不会执行呢?其实这个问题主要要从以下几个方面去考虑:
Q:
跨域究竟是谁的策略?
A:
浏览器。
Q:
在什么时机会拦截请求?
A:
请求一定是先发出去,在返回来的时候被浏览器拦截了,如果请求是有返回值的,会被浏览器隐藏掉。
Q:
究竟什么时候会发预检请求?
A:
复杂请求。
Q
:非简单请求如果有预检,请求什么时候会被真正执行?
A
:预检请求返回允许跨域的相关头部时。
简单请求:不管是否跨域,只要发出去了,一定会到达服务端并被执行,浏览器只会隐藏返回值(拦截响应)
复杂请求:先发预检,预检不会真正执行业务逻辑,预检通过后才会发送真正请求并在服务端被执行
网友评论