• AJAX跨域实战


    本文目的

    今天终于梳理清楚了AJAX跨站请求的原理和解决方案,在此记录下,作为备忘。

    浏览器同源策略

    同源策略又名同域策略是浏览器中的主要安全措施。这里的“源”指的是主机名协议端口号的组合;我们可以把一个“源”看作是某个web页面或浏览器所浏览的信息的创建者。 同源策略,简单地说就是要求动态内容(例如,JavaScript或者VBScript)只能阅读与之同源的那些HTTP应答和cookies,而不能阅读来自不同源的内容。更为有趣的是,同源策略对写操作没有任何限制。因而,一个web站点可以向任何其他的Web站点发送(或写入)HTTP请求,尽管为 了防止跨站请求可能会对发送这些请求有关的cookies和头部有所限制。(以上描述来之网络

    通俗的讲:同源策略就浏览器不允许是站点A的js脚本访问站点B提供的动态数据,因为这样可能带来安全隐患

    如何跨域

    跨域就是绕过同源策略限制,使得站点A的js脚本可以访问到站点B提供的数据。怎么绕过呢?比较常见跨域方案是使用代理,即在A站点下搭建一个代理(可以是个自己的CGI),让代理访问B站点,并将结果反给A页面,这种方法的可扩展性不够好,实施成本大。目前比较经典的方案使用JSONP方式(json with padding)。从上面的定义中,可以知道浏览器不允许A的js脚本访问B提供的数据,但是没有阻止拉取B站点提供的静态资源,如js文件,图片等。所以,跨域的关键在于如何利用好这些“静态”的内容。举个例子:

    A站点需要访问B站点的数据,B站点有下面的脚本(PHP编写的cgi):

    <?php
    echo json_encode(array(‘msg’=>’cross domain access’));
    ?>

    这样是无法拿到数据的,因为B站点吐出的是json数据,如下:

    {“msg”:”cross domain access”}

    但如果将B站点的脚本改成下面的样子,站点A就可以访问到数据。

    <?php
    echo ‘localFunc(’. json_encode(array(‘msg’=>’cross domain access’)). ‘);’;
    ?>

    因为此时,返回的结果如下:

    localFunc({“msg”:”cross domain access”});

    没错,是一个函数调用,可以理解为脚本,而不是数据,浏览器认为合法,所以允许访问。当然,localFunc函数需要在A站点的页面定义。

    script标签跨域

    上面描述了原理,接下来描述具体如何实时。首先,我们需要搭建两个站点,我的实验环境是LAMP,所以在apache中设置了两个virtual host: http://a.oa.comhttp://b.oa.com

    搭建好后,将文件index.html拷贝到站点A根目录

    <!DOCTYPE html>
    <html>
        <!--A站点首页 index.html-->
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
            <script type="text/javascript" src="http://code.jquery.com/jquery-1.8.1.min.js "></script>
            <title>cross domain demo</title>
        </head>
        <body>
            <input type="button" value="JSONP跨站原理" onclick="onClickCrossJSONPTheory();"></input><br/>
            <input type="button" value="JSONP跨站jquery简化后版本" onclick="onClickCrossJSONP();"></input><br/>
            <input type="button" value="getScript跨站" onclick="onClickJQueryScript();"></input><br/>
        </body>
        <script>
            function localFunc(data) {
                alert(data.msg);
            }
            function onClickCrossJSONPTheory() {
                var script = document.createElement("script");
                script.type = "text/javascript";
                script.src = "http://b.oa.com/index.php?callback=localFunc";
                document.getElementsByTagName('head')[0].appendChild(script);
                // 省略删除
            } 
            function onClickCrossJSONP() {
                $.getJSON('http://b.oa.com/index.php?callback=?', function(json) {
                    alert(json.msg);
                });
            }
            function onClickJQueryScript() {
                $.getScript('http://b.oa.com/alert.js', function(){
                    cross();
                    cross();
                });
            }
        </script>
    </html>

    将index.php文件拷贝到B站点根目录

    <?php
    // B站点首页: index.php
    echo $_GET['callback'] . '(' . json_encode(array('msg'=>'hello cross-domain')) . ');';
    ?>

    为A站点和B站点配上host(很重要),打开浏览器,输入“http://a.oa.com”,得到如下页面:

    clip_image002

    点击第一个按纽会弹出对话框,答应站点B的内容,如下:

    clip_image004

    我们看看index.html中都做了些什么:

    1. 定义回调函数localFunc

    2. 在onClickCrossJSONPTheory函数中动态加载script标签

    3. 将localFunc作为url参数

    4. 清理创建的标签(省略),如果不清理,script标签会越来越多。

    而B站点将传过来的回调函数包装上(padding)自己的数据(JSON),返回给A站点。

    这么简单,就“骗”过了浏览器,不是吗?

    $.getJSON跨域

    上面的步骤是不是有点麻烦,除了自定义函数需要根据不同业务逻辑而变化,其他步骤全部都是一样,所以这些基本上可以提取出来重用。

    好在jquery提供了这样的机制。点击页面上的第二个按钮,实现了同样的功能,但是用了3行代码(onClickCrossJSONP函数中的实现),其他的工作jquery帮我们做了。我们只需要在$.getJSON的url参数中添加一个回调参数,值用问号“”代替,如下:

    clip_image006

    这样jquery框架会自动填充一个唯一的函数名称,也就是后面匿名回调函数的名称,http抓包显示如下:

    clip_image008

    $.getScript跨域

    最后,捎带说明一下$.getScript函数,用法与getJSON类似,只不过它可以直接和js文件交互,而不是cgi,列子如上,需要在B站点根目录下添加alert.js文件,如下:

    // 定义函数
    function cross() {
        alert('cross domain execute');
    }
    
    // 调用函数
    cross();

    点击A站点首页的第三个按钮,可以发现弹出了三次对话框,说明getScript加载js后,会执行它,然后回调函数的中也可以调用相关函数和对象。

    总结

    1. 浏览器同源策略是基于安全的考虑强制执行
    2. 跨域方法:1)代理; 2)JSONP两种方式进行跨域操作(推荐)
    3. jquery框架的$.getJSON可以简化JSONP的实现过程
    4. JSONP需要CGI做出调整,返回的数据必须是js代码(函数调用),而不是json数据。

    参考资料

  • 相关阅读:
    activity生命周期
    logcat
    URI
    intent Filter
    隐式intent
    intent
    訪问远程WAMP 下phpmyadmin
    CFileDialog的使用方法简单介绍
    JAVA wait(), notify(),sleep具体解释
    Android开发之去掉标题栏的三种方法,推荐第三种
  • 原文地址:https://www.cnblogs.com/bourneli/p/2682116.html
Copyright © 2020-2023  润新知