zoukankan      html  css  js  c++  java
  • JS 跨域认识及如何解决

    什么是跨域

    指的是浏览器不允许javascrip脚本向其他域名发起ajax请求。

    跨域的各种情况判定

    URL                      说明       是否允许通信
    http://www.a.com/a.js
    http://www.a.com/b.js     同一域名下   允许
    http://www.a.com/lab/a.js
    http://www.a.com/script/b.js 同一域名下不同文件夹 允许
    http://www.a.com:8000/a.js
    http://www.a.com/b.js     同一域名,不同端口  不允许
    http://www.a.com/a.js
    https://www.a.com/b.js 同一域名,不同协议 不允许
    http://www.a.com/a.js
    http://70.32.92.74/b.js 域名和域名对应ip 不允许
    http://www.a.com/a.js
    http://script.a.com/b.js 主域相同,子域不同 不允许
    http://www.a.com/a.js
    http://a.com/b.js 同一域名,不同二级域名(同上) 不允许(cookie这种情况下也不允许访问)
    http://www.cnblogs.com/a.js
    http://www.a.com/b.js 不同域名 不允许

    解决办法:

    JSONP

    <script> 标签是不受同源策略的限制的,它可以载入任意地方的 JavaScript 文件,而并不要求同源。

    所以 JSONP 的理念就是,我和服务端约定好一个函数名,当我请求文件的时候,服务端返回一段 JavaScript。这段 JavaScript 调用了我们约定好的函数,并且将数据当做参数传入。非常巧合的一点(其实并不是),JSON 的数据格式和 JavaScript 语言里对象的格式正好相同。所以在我们约定的函数里面可以直接使用这个对象。

    光说不练假把式,让我们来看一个例子:

    你需要获取数据的页面 index.html:

    <script>
        function getWeather(data) {
            console.log(data);
        }
    </script>
    
    <script src="http://x.y.com/xx.js">

    http://x.y.com/xx.js 文件内容:

     
    getWeather({
        "城市": "北京",
        "天气": "大雾"
    });

    我们可以看到,在我们定义了 getWeather(data) 这个函数后,直接载入了 xx.js。
    在这个脚本中,执行了 getWeather 函数,并传入了一个对象。然后我们在这个函数中将这个对象输出到 console 中。

    这就是整个 JSONP 的流程。

    跨资源共享(CORS)

    通过修改document.domain来跨子域

    浏览器都有一个同源策略,其限制之一就是第一种方法中我们说的不能通过ajax的方法去请求不同源中的文档。 它的第二个限制是浏览器中不同域的框架之间是不能进行js的交互操作的。
    不同的框架之间是可以获取window对象的,但却无法获取相应的属性和方法。比如,有一个页面,它的地址是http://www.example.com/a.html , 在这个页面里面有一个iframe,它的src是http://example.com/b.html, 很显然,这个页面与它里面的iframe框架是不同域的,所以我们是无法通过在页面中书写js代码来获取iframe中的东西的:

    <script type="text/javascript">
        function test(){
            var iframe = document.getElementById('ifame');
            var win = document.contentWindow;//可以获取到iframe里的window对象,但该window对象的属性和方法几乎是不可用的
            var doc = win.document;//这里获取不到iframe里的document对象
            var name = win.name;//这里同样获取不到window对象的name属性
        }
    </script>
    <iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe>
    

    这个时候,document.domain就可以派上用场了,我们只要把http://www.example.com/a.html 和 http://example.com/b.html这两个页面的document.domain都设成相同的域名就可以了。但要注意的是,document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。

    1.在页面 http://www.example.com/a.html 中设置document.domain:

    <iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe>
    <script type="text/javascript">
        document.domain = 'example.com';//设置成主域
        function test(){
            alert(document.getElementById('iframe').contentWindow);//contentWindow 可取得子窗口的 window 对象
        }
    </script>
    

    2.在页面 http://example.com/b.html 中也设置document.domain:

    <script type="text/javascript">
        document.domain = 'example.com';//在iframe载入这个页面也设置document.domain,使之与主页面的document.domain相同
    </script>
    

    修改document.domain的方法只适用于不同子域的框架间的交互。

    使用window.name来进行跨域

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

    使用HTML5的window.postMessage方法跨域

    在 HTML5 中, window 对象增加了一个非常有用的方法:

    windowObj.postMessage(message, targetOrigin);
    • windowObj: 接受消息的 Window 对象。

    • message: 在最新的浏览器中可以是对象。

    • targetOrigin: 目标的源,* 表示任意。

    这个方法非常强大,无视协议,端口,域名的不同。下面是烤熟的栗子:

    var windowObj = window; // 可以是其他的 Window 对象的引用
    var data = null;
    
    addEventListener('message', function(e){
        if(e.origin == 'http://jasonkid.github.io/fezone') {
            data = e.data;
            
            e.source.postMessage('Got it!', '*');
        }
    });

    message 事件就是用来接收 postMessage 发送过来的请求的。函数参数的属性有以下几个:

    • origin: 发送消息的 window 的源。

    • data: 数据。

    • source: 发送消息的 Window 对象。

    引用:

    https://segmentfault.com/a/1190000000718840

    https://segmentfault.com/a/1190000003642057

  • 相关阅读:
    markdown syntax
    solidity_mapping_implementation
    paramiko 模块安装和使用
    检测服务运行的脚本
    系统非正常关机启动后出现:an error occurred during the file system
    bacula 备份恢复
    socket 网络编程
    Python 8 协程/异步IO
    Linux系统通过console口连接交换机
    Python 7 多线程及进程
  • 原文地址:https://www.cnblogs.com/linyihai/p/7172057.html
Copyright © 2011-2022 走看看