同源策略
同源策略就是,不同协议,域名,端口的站点无法直接进行请求。同源策略只针对浏览器,浏览器一旦检测到请求的结果域名不一致时,就会堵塞请求结果。记住:
跨域请求会发送成功,但是返回的结果会被浏览器堵塞
为什么需要同源策略
比如说我们进行网银转账,真实的站点是 bank.com ,但是有一天没看清楚进入了 bang.com,而bang.com中借助iframe(src = bank.com)使得页面看上去跟bank.com完全一样,这个时候,如果没有同源策略,我们在iframe中填入的账号密码就可能在iframe之外被获取到。正因为有了同源策略,不同源站点之间无法直接进行信息的获取,才能使我们的站点更加安全。
而为什么只限制读,而不限制写呢?如果无法将请求发送出去,那就从源头上阻断了网站之间的信息共享。同时,在一般情况下,限制读已经能够满足站点的安全需求了。
如何解决跨域问题
1、跨域资源共享(CORS)
通过后端代码在返回数据的header中设置:
Access-Control-Allow-Origin:*
*表示所有网站都可以获取到接口数据,同样可以设置为只针对某个站点:
Access-Control-Allow-Origin:'https://site.com'
这样就只支持 https://site.com 访问了
2、JSONP
JSONP的原理是利用了script标签的跨域性,浏览器通过script标签先服务端发送一个请求,并且带上一个回调函数名称,而服务端接收到请求后,就将浏览器需要的数据做为回调函数的参数,然后将整个函数调用返回:
<script src="http://testApi.com/callback=cb"></script>
<script>
let resData='';
function cb(data) {
resData=data;
}
</script>
这里的script标签一般都是动态创建的
服务端的代码可能是这样的:
let data='test string';
response.end(callback+'('+data+')')
这样就实现了通过jsonp来进行跨域请求。JSONP的优点在于兼容性好,缺点在于只能发送get请求,对于其他请求无能为力。
3、iframe跨父窗口
不同源的iframe可以读取到父窗口的window对象,可以通过调用:
window.parent
来进行获取
4、window.postMessage
父窗口可以通过postMessage的方法向子iframe传递数据,而子iframe中可以通过事件触发的方式获取到数据;
比如,http://localhost:8000 中存在 http://localhost:9000 的iframe,
(1)父窗口向子窗口发送数据(8000=>9000):
window.function(){
window.frames[0].postMessage('this is from 8000','http://localhost:9000')
}
而9000窗口需要绑定message事件接收数据:
window.addEventListener('message',function(event){
console.log(event)//通过event.origin可以判断数据来源
})
(2)子窗口向父窗口传递数据(9000=>8000):
window.parent.postMessage('this is from 9000','http://localhost:8000');
其中postMessage的参数如下(MDN):
通过这种方式可以实现借助iframe进行授权登录的功能(iframe中授权登录成功时,通过postMessage将信息传递给父窗口)
5、通过后端写一个代理服务器
通过后端写一个代理服务器的方式,因为同源策略只存在于浏览器,因此可以通过请求同域的后端服务器,然后在这个服务中进行代理请求其他的接口。
参考 李银城《高效前端:Web高效编程与优化实践》,强烈推荐