• JavaScript 实现跨域的常用方法


      新手在练习Ajax的时候经常会出现“莫名其妙”的bug,代码都对,但是测试的时候控制台报错,原因可能就是测试文件路径有问题,导致了Ajax的跨域问题。跨域问题在开发过程中并不是很常见,但是还是有的,总结下常见的跨域访问的方法:

    一、利用JSONP

    <script type="text/javascript">
    function handler(json-data) {
        //对获得的json数据进行处理
    }
    </script>
    <script src="http://example.com/request.php?callback=handler"></script>

    PS: 参数名可以不叫callback,但是一般都叫这个。

    第二个script标签返回的内容会被当做JavaScript内容处理,所以服务器端可以这样写

    <?php 
    $callback = $_GET['callback'];  // 获得回调函数
    $data = array('a','b','c');            // 数据
    echo $callback.'('.json_encode($data).')'; // 拼接输出 相当于输出JS:callback(json-data);
    ?>

    这样就能处理数据了。

    jQuery可以这样写:

    <script type="text/javascript">
    $.getJSON('http://example.com/request.php?callback=?', function(json-data) {
        //处理数据
    })
    </script>

    二、利用Window.domain

    如果主页是http://www.example.com/a.html页面,iframe是http://example.com/b.html页面就会存在跨域问题:

    <script type="text/javascript">
    function onLoad() {
        var iframe = document.getElementById('iframe');
        var win = iframe.contentWindow; //这里能够获取到iframe的window对象,但是意义不大
        var doc = win.document; //这里获取不到iframe的document对象
        var doc = win.name; //同样获取不到windows对象的name
        ...
    }
    </script>
    <iframe src="http://example.com/b.html" onload="onLoad()" id="iframe"></iframe>

    解决方法:

    我们只要把http://www.example.com/a.html 和http://example.com/b.html这两个页面的document.domain都设成相同的域名就可以了。但要注意的是,document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。例如:a.b.example.com 中某个文档的document.domain 可以设成a.b.example.com、b.example.com 、example.com中的任意一个,但是不可以设成 c.a.b.example.com,因为这是当前域的子域,也不可以设成baidu.com,因为主域已经不相同了。

    主页脚本:

    <script type="text/javascript">
    function onLoad() {
        document.domain = 'example.com';
        function test() {
            alert(document.getElementById('iframe').contentWindow);
        }
    }
    </script>
    <iframe src="http://example.com/b.html" onload="test()" id="iframe"></iframe>

    iframe脚本:

    <script type="text/javascript">
    document.domain = 'example.com';
    </script>

    三、利用window.name || location.hash

    演示window.name,给name赋的值必须是字符串,而且大小不能太大,最大2M左右。如果需要传其他的数据可以转换成JSON字符串。

    <!-- a页面的脚本,3s后跳转到b页面 -->
    <script type="text/javascript">
    window.name = '页面a设置的值';
    setTimeout(function() {
        window.location = 'b.html';
    }, 3000);
    </script>
    
    <!-- b页面的脚本 -->
    <script type="text/javascript">
    alert(window.name); //获取到window.name 的值
    </script>

    利用这个特性,同样认为所请求的页面数据和主页数据不同源:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>跨域</title>
    <script type="text/javascript">
    function getData() {
        var iframe = document.getElementById('proxy');
        iframe.onload = function() {
            var data = iframe.contentWindow.name;//iframe把数据放在了window.name里
            alert(data);
        };
        iframe.src = 'b.html';//不一定是b.html,只要和a.html同源即可,比如about:blank。这样iframe跳转到和a.html同源下,但是window.name没有发生改变,a.html就可以获取到!
    }
    </script>
    </head>
    <body>
        <!-- 不让iframe显现出来,iframe只是帮助跨域的 -->
        <iframe src="http://www.example.com/data.html" style="display: none;" onload="getData()" id="proxy"></iframe>
    </body>
    </html>

    四、利用html5,postMessage()方法

    <!-- http://test.com/a.html的代码 -->
    <script type="text/javascript">
    function onLoad(){
        var iframe = document.getElementById('iframe');
        var win = iframe.contentWindow;
        win.postMessage('我是 a 页面');
    }
    </script>
    <iframe src="http://www.test.com/b.html" id="iframe" onload="onLoad()"></iframe>
    
    <!-- http://www.test.com/b.html的代码 -->
    <script type="text/javascript">
    window.onmessage = function(e) {
        e = e || event;
        alert(e.data); //也可以从iframe发到window
    };
    </script>
    五、CORS
    这是服务器端允许脚本跨域,header("Access-Control-Allow-Origin: http://www.a.com"); 或者将请求发回服务器,然后让服务器完成请求再返回给客户端!
    六、图像Ping
    <script type="text/javascript">
    var img = new Image();
    img.onload = img.onerror = function() {
        alert('OK');
    };
    //之所以能把onload和error写成同一个事件,因为这种跨域方式是单向的,只能从客户端向服务器端发送数据而客户端接受不到服务器端的数据
    img.src = "http://www.example.com/test?name=kiscall";
    </script>

    七、Comet

    Comet有两种实现方式,长轮询和流。

    短轮询:

    长轮询:

    服务器实现流的方法:

    <?php 
        $i = 0;
        while(true) {
            echo "data";
            flush();
            sleep(10);
            $i++;
        }
    ?>

    八、SSE和WebSockets就没时间介绍了!

    注: 部分内容参考自http://www.cnblogs.com/2050/p/3191744.html

  • 相关阅读:
    Debian下修改/etc/fstab出错致系统无法启动修正
    三种管理方法[书摘]
    Windows Phone & Windows 8 Push Notification from Windows Azure
    Windows Phone 8 如何在内存与硬件受限的设备上开发
    Windows Phone 8 获取与监听网络连接状态
    Windows Phone 处理 MessageBox导致的应用异常退出以及使用代码方式退出应用
    Windows store 应用调用 SharePoint Service
    嵌入式成长轨迹61 【智能家居项目】【ARM 飞凌ok6410】【在虚拟机Ubuntu下NFS网络文件系统建立】
    嵌入式成长轨迹65 【智能家居项目】【ARM 飞凌ok6410】【飞凌开发板——SD卡一键烧写】
    嵌入式成长轨迹63 【智能家居项目】【ARM 飞凌ok6410】【ARM QT 移植环境搭建问题集锦】
  • 原文地址:https://www.cnblogs.com/kiscall/p/4741801.html
Copyright © 2020-2023  润新知