前端新人百问(1)跨域是什么

前言

本人开始接触前端有一年左右,期间遇到了许多问题,有些问题在当下被解决之后,再次遇到还是会有些模糊和不解。与其说是新人百问,不如说是我自己的百问,希望能整理出来这些知识供自己回顾,也供大家学习和指点。

什么是跨域

在前端部分,我们通常所说的跨域指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对javascript施加的安全限制。
例如:页面A想获取页面B的资源,如果A、B页面的协议、域名、端口不同,所进行的访问行动都是跨域的,而浏览器为了安全问题一般都限制了跨域访问,也就是不允许跨域请求资源。

同源策略:是指协议,域名,端口都要相同,其中有一个不同都会产生跨域;
同源策略限制了以下行为:

  1. Cookie、LocalStorage 和 IndexDB 无法读取
  2. DOM 和 JS 对象无法获取
  3. Ajax请求发送不出去

发生跨域的三个必要条件

  1. 浏览器限制: 即浏览器对跨域行为进行检测和阻止;
  2. 触发跨域的三要素之一:即 协议,域名和端口三个条件满足其一
  3. 发起的是xhr请求: 即发起的是XMLHttpRequest类型的请求。
    其实xhr请求才是设计者们设计跨域的最关键的条件因素。并且只有同时满足三个条件才能触发跨域问题。

常见的跨域场景

http://www.baidu.cn/index.html 调用   http://www.baidu.cn/server.php  非跨域

http://www.baidu.cn/index.html 调用   http://www.google.cn/server.php  跨域,主域名不同

http://www.baidu.cn/index.html 调用   http://script.baidu.cn/server.php  跨域,主域相同,子域名不同

http://www.baidu.cn:8080/index.html 调用   http://www.baidu.cn/server.php  跨域,端口不同

https://www.baidu.cn/index.html 调用   http://www.baidu.cn/server.php  跨域,协议不同

localhost   调用 127.0.0.1 跨域

解决跨域的常见方法

1.jsonp解决跨域问题

比如你有一个页面index.html,需要从不同的域里获取json数据,数据地址为“http://demo.com/data.php”,那么你就可以在html页面中这样写:

<script> 
     function do(jsondata){
         //处理数据 
       } 
</script>
<script src="http://demo/data.php?callback=do"></script>

可以看出jsonp的原理就是利用script引入js文件,文件加载成功后执行url中指定的函数,我们需要获取的json数据将会作为参数传入。不过如果数据地址是别人的文件,自己无法操控,那么就得按照提供数据的一方的数据模式来处理。所以使用jsonp方法处理跨域,是需要服务器端的配合。

也可以使用jquery封装$.getJSON()的方法,这个方法很便利,看一下代码:

<script>
    $.getJSON('http://demo/data.php?callback=?’,function(jsondata){
        //处理数据
  });
</script>

jquery会自动生成一个全局函数来替换callback=?中的问号,获取到数据后又会自动销毁。$.getJSON方法会自动判断是否跨域,不跨域,就调用普通的ajax方法;跨域,则会以异步加载js文件的形式来调用jsonp的回调函数。
再以我们常用的AJAX方法为例:

$.ajax({  
        url:"",  
        dataType:'jsonp',  
        data:'',  
        jsonp:'callback',  //传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(默认为:callback)
        success:function(result) {  
            //成功的处理
        },
        error:function(){
            //错误处理
} 
});  

jsonp的缺点:

  1. JSONP是一种非官方的方法,而且这种方法只支持GET方法,不如POST方法安全。。
  2. JSONP的实现需要服务器配合,如果是访问的是第三方的服务器,我们没有修改服务器的权限,那么这种方式是不可行的。

2.window.name+iframe解决跨域

window.name 的美妙之处:name 值在不同的页面(甚至不同域名)加载后依旧存在,我们可以利用这一特性来解决跨域问题。
例如:我们想从从www.example.com/a.html中获取www.demo.com/b.html中的数据,我们可以用一个隐藏的iframe标签来加载b页面,再在a页面里获取iframe的数据。
首先,在a.html中包含:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>解决跨域问题</title>
    <style type="text/css">
        #ifarme{
            display:none;
        }
    </style>
</head>
<body>
    <iframe src="http://www.demo.com/b.html" frameborder="0" onload="getData()" id="ifarme"></iframe>
</body>
<script type="text/javascript">
    function getData(){
        var iframe = document.getElementById("iframe");
        iframe.onload = function(){
            var data = iframe.contentWindow.name;
            console.log(data);
        }
        ifarme.src="about:blank";//这里的src的页面可以随意设置为与a.html同源的页面,空白页about:blank也行。只有同源,a.html才能访问到iframe里面的东西。
    }
</script>
</html>

接着,在b.html中包含:

<script>
  window.name="a页面需要获取的json数据或者字符串";
</script>

这样就解决了跨域问题。

3.postMessage解决跨域

postMessage 是 HTML5 新增加的一项功能,跨文档消息传输(Cross Document Messaging),目前:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 都支持这项功能,使用起来也特别简单。
还是以刚才的例子来实现
首先,在a.html中:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>a.html</title>
</head>
<body>
    <iframe src="http://www.demo.com/b.html" style='display: none;'></iframe>
    <script>
	window.onload = function() {
	    let targetOrigin = 'http://www.demo.com';
	    window.frames[0].postMessage('我要给你发消息了!', targetOrigin);
	}
	window.addEventListener('message', function(e) {
	    console.log('a.html 接收到的消息:', e.data);
	});
    </script>
</body>
</html>

接着,在b.html中:

<script>
    window.addEventListener('message', function(e) {
        if(e.source != window.parent) {
	    return;
        }
        let data = e.data;
        console.log('b.html 接收到的消息:', data);
        parent.postMessage('我已经接收到消息了!', e.origin);
    });
</script>

总结

跨域是工作中经常会遇到的问题,也是非常多前端岗位的必问题目之一,解决跨域的方法还有很多,笔者能力有限,目前只掌握这三种方法,有待补充。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值