javascript跨域实践

上次我转载了一篇 【转】JavaScript最全的10种跨域共享的方法 ,仔细研读,终于对跨域有了一些些了解,做了几个demo加深印象.

1、jsonp 方式跨越:

我首先新建一个服务端页面: jsonp.php ,放在 lovefishss.sinaapp.com 下面,具体路径如下:http://lovefishss.sinaapp.com/cross-domain/jsonp.php,jsonp.php代码如下

$callback = $_GET['callback'];
$key = $_GET['key'];
$domain = 'lovefishss.sinaapp.com';
$data = '{"domain":"'. $domain .'", "key":"'. $key .'"}';
echo $callback . '('. $data .')';

我这里使用 $callback 变量保存通过 callback 传递过来的值(回调函数的名称),使用 $key 保存 key 值,然后构造 json 格式字符串,最后组合输出。

我再新建一个 jsonp.html 的请求发送页面,我把它放在 lovefishs.sinaapp.com 下面,具体路径:http://lovefishs.sinaapp.com/cross-domain/jsonp.html

这里我要着重说明一下,jsonp跨域方式是可以跨任何域的,不要因为我这里只是跨了子域,就被我误导了,如果有疑惑,可以看一下我转载的文章:【转】JavaScript最全的10种跨域共享的方法

jsonp.html 代码:

View Code
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>jsonp 跨域</title>
<meta name="keywords" content="" />
<meta name="description" content="" />
<style type="text/css">
*{margin: 0;padding: 0;}
body {text-align: left;}
button {padding: 5px 10px;}
.demo, .callbackResult {margin: 10px 0;padding: 0 10px;}
</style>
</head>
<body>

<div class="demo">
    <p><button type="button" onclick="jsonp('javascript');">click me(javascript)</button></p>
</div>

<div class="demo">
    <p><button type="button" onclick="jsonp('jquery');">click me(jquery)</button></p>
</div>

<div id="J_DataView" class="callbackResult"></div>

</body>
<script type="text/javascript" src="../static/lib/jquery.1.7.2.min.js"></script>
<script type="text/javascript">
function fRandomBy(under, over){
    switch(arguments.length){
        case 1: return parseInt(Math.random() * under + 1);
        case 2: return parseInt(Math.random() * (over-under+1) + under);
        default: return 0;
    }
}

function jsonp(type){
    var key = fRandomBy(10000);
    var url = 'http://lovefishss.sinaapp.com/cross-domain/jsonp.php?callback=callback&key=' + key;
    switch(type){
        case 'javascript':
            var jsonpScript =document.getElementById('J_JsonpScript');
            if(jsonpScript){
                jsonpScript.parentNode.removeChild(jsonpScript);
            }
            var script =document.createElement('script');
            script.setAttribute('type', 'text/javascript');
            script.setAttribute('src', url);
            script.setAttribute('id', 'J_JsonpScript');
            document.getElementsByTagName('head')[0].appendChild(script);
            break;
        case 'jquery':
            $.ajax({
                type: 'get',
                url: url,
                data: {key: key},
                dataType: 'jsonp',
                success: callback,
                error: function(){
                    
                }
            });
            break;
    }
}
function callback(data){
    var html = [
        '<p>domain:'+ data.domain +'</p>',
        '<p>key:'+ data.key +'</p>'
    ];
    var dataView = document.getElementById('J_DataView');
    dataView.innerHTML = dataView.innerHTML + html.join('');
}
</script>
</html>

我这里写了2种方式,一种javascript,一种借助于jquery类库,javascript方式有助于对 jsonp 跨域方式更了解,大家可以好好的看一下源码

jsonp 跨域方式就是这么简单,我觉得它能够胜任大部分的跨域方式,当然,你需要服务端的配合,如果人家服务端不配合你,不论你怎样,都是没用的.

jsonp 比较适用于单向的数据请求,同时还有个缺点就是,信息传输量太少,因为它是get方式传递请求数据,不及post方式数据量大,如果遇上特殊的场景,可能就不适用了,不过不用担心,我下面还会提到其他几种跨域方式,也会有详细的代码和demo参考.

2、document.domain 方式跨域

前段时间,遇到个跨域问题,就是发送当前页面 html 内容到子域 f.domain.com 下的服务端页面处理(生成当前页的快照),但是当前有可能是子域 a.domain.com,或者是 b.domain.com,更或者是 c.domain.com 等等,开始想用 jsonp 方式,但是因为当前页 html 内容比较大,已经超过了 get 提交方式的最大数据量,所以行不通;后面我用 document.domain 跨域解决了这个问题,基本方法如下:

首先,我们在 lovefishss.sinaapp.com(这里使用这个子域作为服务端处理) 域下新建一个代理文件 proxy.html ,具体地址如下:http://lovefishs.sinaapp.com/cross-domain/document.domain.proxy.html ,代码内容如下:

<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>document.domain 跨域 - proxy</title>
<meta name="keywords" content="" />
<meta name="description" content="" />
<style type="text/css">
*{margin: 0;padding: 0;}
</style>
</head>
<body>
</body>
<script type="text/javascript" src="../static/lib/jquery.1.7.2.min.js"></script>
<script type="text/javascript">
document.domain = 'sinaapp.com';
</script>
</html>

代码很简单,也就做了 2 个事,一个引入 jquery(这个我们后面会用到),一个设置 document.domain 值。这个页面的主要作用就是供需要的页面插入iframe,iframe的src就是这个页面的地址。

然后,我们再在 lovefishss.sinaapp.com 下面新建一个php处理页面,处理接收到的数据,取名 document.domain.php ,具体地址:http://lovefishs.sinaapp.com/cross-domain/document.domain.proxy.php,代买如下:

$html = $_POST['html'];
$html = addslashes($html);// addslashes(string) 转义 | StripSlashes(string) 去掉反斜杠
$key = $_POST['key'];
$domain = 'lovefishss.sinaapp.com';
$data = '{"domain":"'. $domain .'", "key":"'. $key .'"}';
echo $data;

这个文件主要就是接收数据,返回json字符串。

然后,我们来创建请求的页面 document.domain.html ,该页面处于 lovefishs.sinaapp.com 域下(不是说只能处于这个域下,随便放在哪里都成,当然,需要与 proxy.html 是同一个主域),地址 http://lovefishs.sinaapp.com/cross-domain/document.domain.html 代码如下:

View Code
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>document.domain 跨域</title>
<meta name="keywords" content="" />
<meta name="description" content="" />
<style type="text/css">
*{margin: 0;padding: 0;}
body {text-align: left;}
button {padding: 5px 10px;}
.demo, .callbackResult {margin: 10px 0;padding: 0 10px;}
body .hide {display: none;}
.proxyIframe {width: 0;height: 0;border: none;}
</style>
</head>
<body>

<div class="demo">
    <p><button type="button" id="J_ClickBtn">click me(document.domain iframe)</button></p>
</div>

<div id="J_DataView" class="callbackResult"></div>

<script type="text/javascript" src="../static/lib/jquery.1.7.2.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
    function fRandomBy(under, over){
        switch(arguments.length){
            case 1: return parseInt(Math.random() * under + 1);
            case 2: return parseInt(Math.random() * (over-under+1) + under);
            default: return 0;
        }
    }

    function documentDomain(){
        // 大前提:当前域 与 目标域 主域相同,且互相设置了相同的 document.domain = 主域
        document.domain = 'sinaapp.com';
        var $this = $(this);
        var key = fRandomBy(10000);
        var ajaxUrl = 'http://lovefishss.sinaapp.com/cross-domain/document.domain.php', html = $('html').html().replace(new RegExp("<script(.|\n|\r|\t)*<\/script>", "ig"), "");
        var iframeSrc = 'http://lovefishss.sinaapp.com/cross-domain/document.domain.proxy.html';
        var $iframe = $('#J_ProxyIframe'), iframe$;
        var ajaxData = {html: html, key: key};
        if(!$iframe.length){
            $iframe = $('<iframe id="J_ProxyIframe" class="proxyIframe" src="'+ iframeSrc +'"></iframe>');
            $iframe.on('load', function(){
                console.log('iframe loaded');
                //$(this)[0].contentWindow.document.domain = 'sinaapp.com';// 异想天开的从这里控制iframe的document对象的domain值,果然是不行的。。。
                // 还是需要在 iframe 页面内设置 document.domain 值
                // 也就是说想要通过 document.domain 方式跨域的话,必须所跨的域proxy.html文件是你能控制的,要不然你从何处设置proxy.html的document.domian呢?
                iframe$ = $(this)[0].contentWindow.$;
                proxyAjax(iframe$, ajaxData, ajaxUrl, $this);
            });
            $('body').append($iframe);
        }else{
            iframe$ = $('#J_ProxyIframe')[0].contentWindow.$;
            proxyAjax(iframe$, ajaxData, ajaxUrl, $this);
        }
    }

    function proxyAjax(i$, data, url, $btn){
        $btn.attr('disabled', true);
        i$.ajax({
            type: 'post',
            url: url,
            data: data,
            dataType: 'json',
            success: function(data){
                $btn.attr('disabled', false);
                callback(data);
            },
            error: function(){}
        });
    }

    function callback(data){
        var html = [
            '<p>domain:'+ data.domain +'</p>',
            //'<p class="hide">html:'+ data.html +'</p>',
            '<p>key:'+ data.key +'</p>'
        ];
        $('#J_DataView').html($('#J_DataView').html() + html.join(''));
    }

    // 绑定事件
    $('#J_ClickBtn').on('click', documentDomain);
});

</script>
</body>
</html>

有点长,但是有注释,仔细想想应该就能懂。这个页面主要是发送数据,发起请求,请求的地址是我们刚才创建好的 http://lovefishs.sinaapp.com/cross-domain/document.domain.proxy.php ,因为不在同一子域下,所以我们改变当前页的 document.domain = 'sinaapp.com'; ,然后创建一个 iframe ,src指向 proxy.html 页面,然后为这个 iframe 绑定 load 事件,在load 后取得iframe页面的 jquery 对象 $ ,我们要用 iframe 的 $ 来发送post请求,这样,我们就解决了跨域发送大数据的难题,同时我们还能接收到服务端返回的json数据,有用吧,哈哈。

(2012-11-16 未完,待续)

 

 

posted @ 2012-11-15 17:28  小鱼儿-lovefishs  阅读(331)  评论(0编辑  收藏  举报