跨域

对跨域的一些总结,方便日后查阅

跨域并非浏览器限制了发起跨站请求,而是跨站请求可以正常发起,但返回结果被浏览器拦截了,有些浏览器不允许从HTTPS协议的域 跨域访问 HTTP协议,比如Chrome和Firefox,这些浏览器在请求还未发出的时候就会拦截请求

  • 同源策略
    如果两个页面拥有相同的协议(protocol),端口,和域名,那么这两个页面就属于同一个源(origin),JavaScript 允许这种同源页面的数据互相通信。
    一般web页面的端口号默认都是80

    例如:http://xxx.com/a.html 协议是http、端口:80、域名:xxx.com

    若非同源,则以下行为会受到限制:

    1. Cookie、LocalStorage 和 IndexedDB 无法读取
    2. DOM 无法获得
    3. AJAX 请求不能发送

跨域方案

  • 经典的JSONP
    回调函数和数据(script标签可以加载并执行其他域JS文件)

    原理:站点A动态插入script标签,通过script标签引入一个js文件,这个js文件载入成功后会执行我们在url参数中指定的函数(站点B把要提供的数据作为参数传给一个站点A定义的全局函数),并且会把我们需要的json数据作为参数传入。

    1
    2
    3
    4
    5
    6
        <script src="http://xxx.com/data.php?callback=dosomething"></script>
    <script type="text/javascript">
    function dosomething(jsondata){
    console.log(jsondata);
    }
    </script>

    js文件载入成功后,会执行我们在url参数中指定的函数(dosomething),并且会把我们需要的json数据(jsondata)作为参数传入。所以再次强调jsonp是需要服务器端的页面进行相应的配合的。

    1
    2
    3
    4
    5
    <?php
    $callback = $_GET['callback'];
    $data = {'name':'XXX',sex:'X',age:'X'};
    echo $callback.'('.json_encode($data).')';
    ?>

    缺点:1、 仅适应于HTTP的Get请求,不支持POST等其它类型的HTTP请求,不能提交大量数据;

    2、 缺乏错误处理机制
    3、 不能解决不同域的两个页面之间如何进行JavaScript调用的问题
    

    优点:1、 兼容性更好,在老版本的浏览器中可以运行

    2、 请求完毕后可以通过调用callback的方式回传结果,方便调用
    
  • 子域名代理
    在不同的子域 + iframe交互的时候,获取到另外一个 iframe 的 window对象是没有问题的,但是获取到的这个window的方法和属性大多数都是不能使用的

    解决方法:document.domain

    例如:A页面:http://xxx.com/a.html,在这个页面里面有一个iframe,它的src是http://y.xxx.com/b.html

    1
    2
    3
    4
    5
    6
    7
    8
    //a.html
    <iframe id = "iframe" src="http://y.xxx.com/b.html" onload = "test()"></iframe>
    <script type="text/javascript">
    document.domain = 'xxx.com';
    function test(){
    alert(document.getElementById('iframe').contentWindow);
    }
    </script>
    1
    2
    3
    4
    //b.html
    <script type="text/javascript">
    document.domain = 'xxx.com';
    </script>

    document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。

  • CORS
    跨域资源共享。定义了必须在访问跨域资源时,浏览器与服务器应该如何沟通.原理就是使用自定义的 HTTP 头部,让服务器能声明 哪些来源可以通过浏览器访问该服务器上的资源,从而决定请求或响应是应该成功还是失败,主要是通过设置响应头的 Access-Control-Allow-Origin 来达到目的的
    more

  • window.name

在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的。

  • window.postMessage()
    使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源