同源策略、几种跨域方式

概念

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详解

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容