美文网首页
js跨域的解决办法

js跨域的解决办法

作者: zhulichao | 来源:发表于2020-07-23 09:19 被阅读0次
    浏览器都有一个同源策略,其限制之一是不能通过ajax的方法去请求不同源中的文档;第二是限制浏览器中不同域的框架之间是不能进行js的交互操作的。但是不同的框架之间(父子或同辈),是能够获取到彼此的window对象的,但却不能使用获取到的window对象的属性和方法,**postMessage方法除外,**可以当做是只能获取到一个几乎无用的window对象。只要协议、域名、端口有任何一个不同,都被当作是不同的域。要解决跨域的问题,我们可以使用以下几种方法:
    
    **方式一、通过jsonp跨域**
    
    jsonp是利用`<script>`标签可以引入不同域上的js脚本文件来实现的,通过script标签引入一个js文件,这个js文件载入成功后会执行我们在url参数中指定的函数,并且会把我们需要的json数据作为参数传入。所以jsonp是需要服务器端的页面进行相应的配合的。
    
    ```
    /*
    js原生写法,通过http://example.com/data.php?callback=dosomething得到的js文件,就是我们之前定义的dosomething函数,并且它的参数就是我们需要的json数据,这样就跨域获得了我们需要的数据。
    */
    <script>
        function dosomething(jsondata) {
            // 相应操作
        }
    </script>
    <script src="http://example.com/data.php?callback=dosomething"></script>
    
    /*
    jQuery写法,jQuery会自动生成一个全局函数来替换callback=?中的问号,之后获取到数据后又会自动销毁。$.getJSON方法会自动判断是否跨域,不跨域就调用普通的ajax方法,跨域会以异步加载js文件的形式来调用jsonp的回调函数。
    */
    <script>
        $.getJSON('http://example.com/data.php?callback=?', function(jsondata){
            // 相应操作
        });
    </script>
    ```
    <br />
    
    **方式二、通过修改document.domain来跨子域**
    
    针对不同域的框架这种情况,是无法通过在页面中书写js代码来获取iframe中的东西的,这个时候可以使用document.domain,把这两个页面的document.domain都设成相同的域名就可以了。但要注意,只能把document.domain设置成自身或更高一级的父域,且主域必须相同,如果当前文档的domain就是要设置的域名,还是必须显示的设置
    document.domain。这样我们就可以通过js访问到iframe中的各种属性和对象了。
    
    `http://www.example.com/a.html`中:
    ```
    <iframe src="http://example.com/b.html" id="iframe" onLoad="test()"></iframe>
    <script>
        document.domain = 'example.com'; // 设置成主域
        function test() {
            alert(document.getElementById('iframe').contentWindow);
        }
    </script>
    ```
    `http://example.com/b.html`中:
    ```
    <script>
        // 在iframe载入的这个页面也设置document.domain,使之与主页面的document.domain相同
    </script>
    ```
    
    但是如果想在a.html页面中通过ajax直接请求b.html页面,即使设置了相同的document.domain也还是不行的,修改document.domain的方法只适用于不同子域的框架间的交互。如果想通过ajax的方法去与不同子域的页面交互,除了使用jsonp的方法外,还可以用一个隐藏的iframe来做一个代理。原理就是让这个iframe载入一个与你想要通过ajax获取数据的目标页面处在相同域的页面,这个iframe中的页面是可以正常使用ajax去获取你要的数据的,然后通过修改document.domain的方法,通过js完全控制这个iframe,这样就可以让iframe去发送ajax请求,然后收到的数据我们也可以获取到。
    
    **方式三、使用window.name来进行跨域**
    
    window.name属性有个特征,即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,即使这些页面是不同域的或url发生变化,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,不会因新页面的载入而进行重置。window.name的值只能是字符串的形式,最大能允许2M左右甚至更大的一个容量,具体取决于不同的浏览器,但一般是够用了。例如`www.example.com/a.html`页面里的js需要获取另一个位于不同域的页面`www.cnblogs.com/data.html`里的数据,示例代码如下:
    
    `www.cnblogs.com/data.html`中:
    ```
    <script>
        window.name = '我就是页面a.html想要的数据,所有可以转化成字符串来传递的数据都可以在这里使用!!!';
    </script>
    ```
    `www.example.com/a.html`中:
    ```
    <!doctype html>
    <html>
        <head>
            <meta charset="utf-8" />
            <title>window.name跨域</title>
            <script>
                function getData() {
                    var iframe = document.getElementById('proxy');
                    // 这个时候a.html与iframe已经是同源了,可以互相访问
                    iframe.onload = function() {
                        // 获取iframe里的window.name,也就是data.html页面给它设置的数据
                        var data = iframe.contentWindow.name;
                        alert(data);
                    };
                    // 这里的b.html为随便的一个页面,只要与a.html同源的就行
                    iframe.src = 'b.html';
                }
            </script>
        </head>
        <body>
            <iframe id="proxy" src="http://www.cnblogs.com/data.html" style="display:none" onload="getData()" />
        </body>
    </html>
    ```
    
    **方式四、使用HTML5中新引进的window.postMessage方法来跨域传送数据**
    
    `window.postMessage(message, targetOrigin)`方法是html5新引进的特性,不支持IE6、7旧浏览器,可以向其它的window对象发送消息,无论这个window对象是属于同源或不同源,该方法的第一个参数message为要发送的消息,类型只能为字符串;第二个参数targetOrigin用来限定接收消息的那个window对象所在的域,如果不想限定域,可以使用通配符 * 。接收消息的window对象,通过监听自身的message事件来获取传过来的消息,消息内容储存在该事件对象的data属性中。
    
    `test.com/a.html`中:
    ```
    <script>
        function onLoad() {
            var iframe = document.getElementById("iframe");
            var win = iframe.contentWindow;
            // 向不同域发送消息
            win.postMessage('我是来自页面a的消息!', '*');
        }
    </script>
    <iframe id="iframe" src="http://www.test.com/b.html" onload="onLoad()" />
    ```
    `www.test.com/b.html`中:
    ```
    <script>
        window.onmessage = function(e) {
            e = e || event;
            alert(e.data);
        }
    </script>
    ```
    

    相关文章

      网友评论

          本文标题:js跨域的解决办法

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