美文网首页
同源策略、几种跨域方式

同源策略、几种跨域方式

作者: 周花花啊 | 来源:发表于2017-02-24 18:27 被阅读0次

    概念

    1、什么是同源策略?

    • URL(Uniform Resource Locator)
      统一资源定位符,俗称网址


      URL组成URL组成
    • 什么是源(origin)

    • 指页面的协议、域名、端口号

    • 通过location.origin可以查看当前页面的源(IE不支持,可以分开写location.protocol;location.hostname;location.port

      页面的源页面的源
    • 什么是同源策略(Same Origin Policy)

    • 是浏览器的一个功能;

    • 同源就是指协议、域名、端口号相同;

    • 不同源的客户端脚本在没明确授权的情况下,不能读写对方的资源;

    • 什么不是同源策略


      引用不是同源策略引用不是同源策略

      上图这种跨站引用资源不受同源策略的限制,这算是浏览器的一个妥协(让你下载别的网站的资源来使用),引用过来并没有去读和写它们的内容。我引用过来的资源就在当前的域名了,可以对当前域名下的资源读写,而不能读写原来域名的资源。如果我不是引用而是发起Ajax请求的话便会受到同源策略的限制。

    • 有什么作用
      浏览器出于安全方面的考虑,不允许跨域调用其他页面的对象,防止恶意网站盗窃数据。但在安全限制的同时也给注入iframe或是Ajax应用上带来了不少的麻烦,所以有时候就必须跨域。

    2、什么是跨域,跨域有几种实现形式?

    • 出于同源策略的限制,不同源的客户端脚本是不能读写对方资源的,而跨域就是突破同源策略的限制,实现跨源通信(协议和端口号不同造成的问题前台是无能为力的)。

    • 跨域的实现形式:
      (1)、降域[document.domain+iframe]:思路是让不同源的变成同源。

      • 通过降域可以使两个一级域名相同, 二级域名不同的网页实现跨域资源共享, 但是ajax请求不能通过这种方式跨域, 只有cookie和iframe形式的跨域可以用降域来实现;
        被同源策略限制被同源策略限制
      • 具体做法是在两个页面文件脚本中都加入document.domain = "jay.com";,这样两个页面的js文件就可以互相通信了。
        跨域成功跨域成功
      • 缺点:
        1、这种方案容易出现大面积的安全问题,只要任何一个子域名被攻击,那么主域名下的信息也会被泄露;
        2、只对iframe形式的跨域有效;
        3、只对带有同样后缀的域名有效;

    (2)、JSONP[JSON with Padding]

    • JSONP和JSON没有任何关系,仅仅是因为最后生成的JS文件中的数据一般是JSON格式的,像这样printData({name: '周花花', age: 20});因此得名;
    • 我们知道a.com可以引用b.com的JS文件,那是不是可以在b.com的JS文件里面放数据?
    • 实现就是a.com和b.com约定好相同的函数名,a.com中定义这个函数,在b.com中包含这个函数名并且在后面加个括号中间放入数据,即数据名({json数据});,但是b.com中的这个东西在a.com看来就是一个函数,它会调用a.com定义的函数。所以在a.com中的函数就被调用并执行,b.com中的数据被当作形参传入a.com定义的函数中。
    • JSONP就是服务端动态的生成JS。由于JSONP的服务者要面对很多服务对象,而这些服务对象各自的本地函数都不一样,所以为了让远程的JS知道它应该调用的本地函数叫什么名字,客户端传一个参数告诉服务端我想要一段调用XXX函数的JS代码,请你返回给我,于是服务器就可以按照客户端的需求来生成JS脚本并响应了。
      客户端代码:
    <!--不建议直接这样引用,我们可以将动态生成script标签封装成一个函数,每次使用的时候直接调用函数-->
    <script src="//www.zhouhuahua.com/data.js?callback=onPrintData"></script>
    <script>   
      //www.zhoupenghui.com请求www.zhouhuahua.com下面的数据    
      //首先定义一个函数,服务端生成的JS会调用并执行这个函数
      function onPrintData(data){        
            console.log(data);    
      }
      //封装一个生成script标签的函数   
      function printData(){       
            var script = document.createElement('script');       
            script.src = "//www.zhouhuahua.com/data.js?callback=onPrintData";
            document.body.appendChild(script);
      }    
      printData();
    </script>
    <!--用jquery实现jsonp调用-->
    <script>
      $(function(){
        $.ajax({
          type: "get",
          url: "//www.zhouhuahua.com/data.js?callback=printData",
          dataType: "jsonp",
          jsonp: "callback",
          jsonpCallback: "printData",
          success: function(data){
            console.log(data);
          },
          error: function(){
            alert('fail');
          }
        });
      });
    </script>
    

    服务器端生成的JS文件:

    onPrintData({    
        name: '周花花',    
        age: 22
    });
    
    跨域请求得到数据跨域请求得到数据
    • 缺点:
      1、安全性问题,所有的网页都能拿到data.js里面的内容,所以需要校验身份。
      2、因为是基于script所以无法触发post请求,只能获取不能写。
      3、可能被注入( callback=alert(something); )。

    (3)、CORS[Cross-Origin Resource Sharing跨域资源共享]

    • b.com声明:我允许a.com来访问我,在响应头添加一个"Access-Control-Allow-Origin:http://www.zhoupenghui.com"即可;
    • a.com中的js发起对b.com的ajax
      客户端正常发起ajax请求:
    <script>
        document.querySelector("#btn").addEventListener('click', function(){
            $.ajax({
                url: '//www.zhouhuahua.com/CORS.php',   //接口地址即请求地址
                type: 'get',   // 请求类型, post 或者 get, 
                data: {   //发送给后台的数据
                    username: document.querySelector('#username').value
                }, 
                success: function(jsonData){   //响应成功(得到的数据可以是对的也可以是不对的,总之会有一个响应)执行这个函数
                    var jsonObject = JSON.parse(jsonData);  //将后台传的字符串转换为JSON对象
                    dealwith(jsonObject);  //这里的处理函数和上面的一样
                }, 
                error: function(){   //失败(没任何响应,比如服务器宕机了啥的)执行这个函数
                    console.log('出错了') 
                 } 
            });
        });
        function dealwith(userInfo){  //对解析出来的JSON对象操作
            //我们可以用从服务器拿到的数据,返回的数据是由后台给的字符串,所以我们还要写php
            var str = '<dt>性别:</dt>';
            str +=  '<dd>'+userInfo.sex+'</dd>';
            str += '<dt>年龄:</dt>';
            str +=  '<dd>'+userInfo.age+'</dd>';
            document.querySelector('#ct').innerHTML = str;
        }
    </script>
    

    服务端只要加一个响应头内容:

    <?php   
        header("Access-Control-Allow-Origin:http://www.zhoupenghui.com");
        header('Content-Type:text/html;charset=utf-8');   
        $usename = $_GET['username'];   
        if($usename === 'kevin'){       
            $ret = array('sex'=>'男', 'age'=>23);   
        }else if($usename === 'david'){       
            $ret = array('sex'=>'男', 'age'=>30);   
        }else{       
            $ret = array('sex'=>'女', 'age'=>18);  
        }  
        echo json_encode($ret);
    
    CORS跨域获取数据CORS跨域获取数据
    • 优缺点:比JSONP强大,支持所有的http请求,JSONP的优势在于支持老式的浏览器以及可以向不支持CORS的网站请求数据。

    (4)、HTML5 postMessage

    • 这是HTML5的一个功能
      语法为:otherWindow.postMessage(message, targetOrigin);
    • 在a.com中用iframe.contentWindow.postMessage('message',targetOrigin )给b.com发送消息,在b.com中给window绑定message事件,如果message触发我先判断是不是a.com发来的数据。
      a.com中代码:
    <iframe id="ifr" src="//www.zhouhuahua.com/postMess.html" frameborder="1"></iframe>
    <script>    
        window.onload = function(){        
            var ifr = document.getElementById("ifr");        
            var targetOrigin = 'http://www.zhouhuahua.com';
            ifr.contentWindow.postMessage('我是来自zhoupenghui.com的数据', targetOrigin);    
        }
    </script>
    

    b.com中代码:

    <script>    
        window.addEventListener('message', function(event){        
            if(event.origin === 'http://www.zhoupenghui.com'){
                console.log('from:'+event.origin);            
                console.log('zhoupenghui传来的数据:'+event.data);        
            }    
        }, false);
    </script>
    
    postMessage跨源通讯postMessage跨源通讯

    (5)、其他hack

    • hash
    • window.name

    3、jsonp的原理是什么?

    • 不同源的页面数据不能互相读写,但是可以通过script标签引用;
    • 在被引用的对象中存放数据;
    • 动态引用的同时,提供一个回调函数来接收数据;
    • JSONP的本质就是动态的添加script标签来调用服务器提供的JS脚本。

    2、CROS是什么?

    • CORS是一个W3C标准,它允许浏览器向跨源服务器发出XMLHttpRequest请求,从而克服ajax只能同源使用的限制。
    • CORS需要浏览器和服务器同时支持,目前所有的浏览器都支持该功能,IE浏览器不能低于IE10。


      CORS的兼容性CORS的兼容性
    • 当我们读取另一个站点的资源时,支持CORS的浏览器实际上就已经帮我们发起跨站请求了,只是我们没有得到对方网站的允许,所以浏览器将返回的结果拦截,告诉你不能跨域请求资源。只有当对方允许你读取之后,浏览器才会返回你想要的信息。

    练习

    1、在本地搭建服务器,演示同源策略

    • 本地搭建服务器,多站点配置:


      xampp本地多站点配置xampp本地多站点配置
    • 修改本地hosts文件,让多个不同域名映射到本地服务器:


      本地hosts文件修改本地hosts文件修改
      不同域名访问本地服务器不同域名访问本地服务器
    • www.zhoupenghui.comwww.zhouhuahua.com发送ajax请求失败,就是受浏览器同源策略的限制。
      同源策略限制不同域名之间通信同源策略限制不同域名之间通信

    参考:
    JavaScript跨域总结与解决办法
    说说json和jsonp
    跨域资源共享 CORS详解

    相关文章

      网友评论

          本文标题:同源策略、几种跨域方式

          本文链接:https://www.haomeiwen.com/subject/dcsuittx.html