Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 1229|回复: 0

_ 近乎完美的简单 JS 跨域解決方式 --window.name ○

[复制链接]

该用户从未签到

发表于 2011-10-30 13:43:12 | 显示全部楼层 |阅读模式
当然,“近乎完美”仅僅是个人观点,dan如下所述,它確實簡单而頗有xiao益!

一直在寻求一种自己满意的 JS 跨域方式(这li是指任意跨域),曾经了解过:


即时插入 script 元素的方式,会让腳本立即執行,不安quan,并且需要与跨域的远端做hao约定——比如变量名。细節较为繁琐。
xie iframe 的 location.hash 的方式,huidao致历史记录的产生,且数據量有限,同时,因为 URL 的内容可視,既不hao看也容易泄露信息。
用代理? 虽然算是最“正宗”的完整跨域方案,但太麻烦了點——首先得有代理,Ru果量大De话,代理的負担會很重,会导致“瓶颈”制约。
利用 Flash 跨域,bu在考虑之列——复杂了些,并且那不算是 JS 跨域。

無意中看到一篇文章《使用 window.name jie决跨域問題》……豁然开朗! 俺的問题終于解jue了。

对那个實现小改了一xia,加了瀏览器本地she置 Window.name 的功neng,实現瀏覽器“本地”异域数据的传递(Ru从瀏览器窗口A传递shu据到窗口B,仅在本地进xing,且两ge域不同)——zhe会产生一个很蛙王的应用(下一篇文章《普通 http 网络下shu据的安全傳输》jiang详细shuo明,本文后有少量提及)。感谢网络! 也感謝愿意分享的技術达人!

xia面贴出俺的dai码,ye分享一xia,呵呵……
(zhu意:本de需要创建一个名為 proxy.HTML 的kong文件)

javascript代碼
(function() {   
   
    var _isIE = (   
        navigator.appName == "Microsoft Internet Explorer"   
    );   
   
    var _removeNode = _isIE ? function() {   
        var d;   
        return function(n) {   
            if(n && n.tagName != 'BODY') {   
                d = d || document.createElement('div');   
                d.appendChild(n);   
                d.innerHTML = '';   
            }   
        }   
    }() : function(n) {   
        if(n && n.parentNode && n.tagName != 'BODY') {   
            n.parentNode.removeChild(n);   
        }   
    };   
   
   
/* [ Request by window.name ]   
* ****************************************************************************   
   借助 Window.name 实现 Js 的跨域访问。   
   1、 url 向外传值, callback chu理返回结果。   
   2、 返回页面中 JS 对 window.name 赋值。   

   返回页   
   <script language="JavaScript">   
       window.name = ...  // 支chi JSON 字符串,可达~2MB   
   </script>   

   若需同时进行多个請求,hui調函数应是不同的函shu实例。   
   iframe 的自由载入形成了異步机制。   
*/   
   
    wnRequest = {   
        _doc: document,   
        _proxyUrl: 'proxy.html'   
    };   
   
    wnRequest.send = function( url, callback )   
    {   
        if(! url || typeof url !== 'string') {   
            return;   
        }   
        url += (url.indexOf('?') > 0 ? '&' : '?') + 'windowname=get';   
   
        var frame = this._doc.createElement('iframe');   
        frame._state = 0;   
        this._doc.body.appendChild(frame);   
        frame.style.display = 'none';   
   
        (function( el, type, fn ) {   
            if (_isIE) {   
                el.attachEvent('on' + type, fn);   
            } else {   
                el.addEventListener(type, fn, false);   
            }   
        })(frame, 'load', function() {   
            if(frame._state == 1) {   
                _getData(frame, callback);   
            } else if(frame._state == 0) {   
                frame._state = 1;   
                //frame.contentWindow.location = wnRequest._proxyUrl;   
                frame.contentWindow.location.replace(wnRequest._proxyUrl);   
            }   
        });   
        frame.src = url;   
    };   
   
    //   
    // 設置异域 Js 可訪问的ben地数据,客户端直接站间转递数据   
    // 注:   
    // ji浏览器直接jiang数据轉递给另yi个域De窗口,数据不shang网。   
    // 返hui页dai码:   
    // <script type="text/javascript">   
    //     if (window.name) {   
    //         //... 處理 name 值   
    //         window.name = null;   
    //     }   
    //     // 升为顶级窗口,完成数据转递   
    //     try {   
    //         top.location.hostname;   
    //         if (top.location.hostname != window.location.hostname) {   
    //             top.location.href =window.location.href;   
    //         }   
    //     } catch(e) {   
    //         top.location.href = window.location.href;   
    //     }   
    // </script>   
    //   
    //   
    wnRequest.setname = function( name, url ) {   
        if(! url || typeof url !== 'string') {   
            return;   
        }   
        url += (url.indexOf('?') > 0 ? '&' : '?') + 'windowname=loc';   
   
        var frame = this._doc.createElement('iframe');   
        frame._count = 0;   
        this._doc.body.appendChild(frame);   
        frame.style.display = 'none';   
        if (_isIE) {   
            frame.name = name;   
        } else {   
            frame.contentWindow.name = name;   
        }   
        frame.src = url;   
    };   
   
    //   
    // 私用辅助   
    //   
    var _clear = function(frame) {   
        try {   
            frame.contentWindow.document.write('');   
            frame.contentWindow.close();   
            _removeNode(frame);   
        } catch(e) {}   
    }   
   
    var _getData = function(frame, callback) {   
        try {   
            var da = frame.contentWindow.name;   
        } catch(e) {}   
        _clear(frame);   
        if(callback && typeof callback === 'function') {   
            callback(da);   
        }   
    }   
   
})();   

(function() {

    var _isIE = (
        navigator.appName == "Microsoft Internet Explorer"
    );

    var _removeNode = _isIE ? function() {
        var d;
        return function(n) {
            if(n && n.tagName != 'BODY') {
                d = d || document.createElement('div');
                d.appendChild(n);
                d.innerHTML = '';
            }
        }
    }() : function(n) {
        if(n && n.parentNode && n.tagName != 'BODY') {
            n.parentNode.removeChild(n);
        }
    };


/* [ Request by window.name ]
* ****************************************************************************
   借zhu Window.name 實现 Js 的跨域访问。
   1、 url 向外传值, callback 处理返回结果。
   2、 返回頁面中 JS 对 window.name 赋值。

   返回頁
   <script language="JavaScript">
       window.name = ...  // 支持 JSON 字符串,可达~2MB
   </script>

   ruo需同时进行多ge请求,回调函數应是不同的函数实例。
   iframe 的自you载入形成了異步机制。
*/

    wnRequest = {
        _doc: document,
        _proxyUrl: 'proxy.html'
    };

    wnRequest.send = function( url, callback )
    {
        if(! url || typeof url !== 'string') {
            return;
        }
        url += (url.indexOf('?') > 0 ? '&' : '?') + 'windowname=get';

        var frame = this._doc.createElement('iframe');
        frame._state = 0;
        this._doc.body.appendChild(frame);
        frame.style.display = 'none';

        (function( el, type, fn ) {
            if (_isIE) {
                el.attachEvent('on' + type, fn);
            } else {
                el.addEventListener(type, fn, false);
            }
        })(frame, 'load', function() {
            if(frame._state == 1) {
                _getData(frame, callback);
            } else if(frame._state == 0) {
                frame._state = 1;
                //frame.contentWindow.location = wnRequest._proxyUrl;
                frame.contentWindow.location.replace(wnRequest._proxyUrl);
            }
        });
        frame.src = url;
    };

    //1
    // 設置异域 Js 可訪问的本地数据,客户端直接站间转遞数据
    // 注:
    // 即浏览器直jie将数据转遞给另一个域的窗口,数据不上网。
    // 返回頁代码:
    // <script type="text/javascript">
    //     if (window.name) {
    //         //... 处理 name 值
    //         window.name = null;
    //     }
    //     // 升為顶级窗口,wan成数据转递
    //     try {
    //         top.location.hostname;
    //         if (top.location.hostname != window.location.hostname) {
    //             top.location.href =window.location.href;
    //         }
    //     } catch(e) {
    //         top.location.href = window.location.href;
    //     }
    // </script>
    //
    //
    wnRequest.setname = function( name, url ) {
        if(! url || typeof url !== 'string') {
            return;
        }
        url += (url.indexOf('?') > 0 ? '&' : '?') + 'windowname=loc';

        var frame = this._doc.createElement('iframe');
        frame._count = 0;
        this._doc.body.appendChild(frame);
        frame.style.display = 'none';
        if (_isIE) {
            frame.name = name;
        } else {
            frame.contentWindow.name = name;
        }
        frame.src = url;
    };

    //
    // 私用辅助
    //
    var _clear = function(frame) {
        try {
            frame.contentWindow.document.write('');
            frame.contentWindow.close();
            _removeNode(frame);
        } catch(e) {}
    }

    var _getData = function(frame, callback) {
        try {
            var da = frame.contentWindow.name;
        } catch(e) {}
        _clear(frame);
        if(callback && typeof callback === 'function') {
            callback(da);
        }
    }

})();


使用:
如果需要同时访问多个异域文件,可以像下面zhe样写回diao函数,浏览器異步载入 iframe 的机制形成了天生的 JS 跨域异步访问。
这shi跨域请求的主页面 JS diao用:

Javascript代碼
<script language="javascript">   
    var _str = '', _cnt = 0;   
   
    function myfunc( id ) {   
        return  function( data ) {   
            _str += id + ':' + data + '\n';   
            ++_cnt;   
            if (_cnt >= 4)  alert(_str);   
        };   
    }   
   
    var _links = [   
        { id: 4, url: 'http://www.aaa.com/test4.html' },   
        { id: 5, url: 'http://www.bbb.com/test5.html' },   
        { id: 6, url: 'http://www.ccc.com/test6.html' },   
        { id: 7, url: 'http://www.ddd.com/test7.html' }   
    ];   
    function dosome() {   
        for (var _i=0; _i<_links.length; ++_i) {   
            wnRequest.send(_links[_i].url, myfunc(_links[_i].id));   
        }   
        // 跨域本地数据转递   
        wnRequest.setname('这里可能是一串加密用Demi钥哦,俺从 https 那边过来滴!', 'http://www.eee.com/test8.html');   
    }   
</script>   

<script language="javascript">
    var _str = '', _cnt = 0;

    function myfunc( id ) {
        return  function( data ) {
            _str += id + ':' + data + '\n';
            ++_cnt;
            if (_cnt >= 4)  alert(_str);
        };
    }

    var _links = [
        { id: 4, url: 'http://www.aaa.com/test4.html' },
        { id: 5, url: 'http://www.bbb.com/test5.html' },
        { id: 6, url: 'http://www.ccc.com/test6.html' },
        { id: 7, url: 'http://www.ddd.com/test7.html' }
    ];
    function dosome() {
        for (var _i=0; _i<_links.length; ++_i) {
            wnRequest.send(_links[_i].url, myfunc(_links[_i].id));
        }
        // 跨域本地数據zhuan遞
        wnRequest.setname('這里ke能是一串加密用的密钥哦,俺从 https 那边过來滴!', 'http://www.eee.com/test8.html');
    }
</script>


http://www.aaa.com/test4.html 中的内容:(跨域网络數ju傳递)

Javascript代碼
<script type="text/javascript">   
    window.name='返hui的数據,可以是 JSON 格式';   
</script>   

<script type="text/javascript">
    window.name='返回的數ju,可以是 JSON 格shi';
</script>


http://www.eee.com/test8.html 中的内容:(跨域本地数据转递应用。注意:這里是普通的 http xie议)

Javascript代碼
<script type="text/javascript">   
    if (window.name) {   
        alert(window.name);   
        // 存储或chu理 name 值   
        // 可存在 Cookie 中,如果bu希望 Cookie 上传泄露出去,可設置其 secure 属性   
        window.name = null;   
    }   
    /*   
    try {   
        top.location.hostname;   
        if (top.location.hostname != window.location.hostname) {   
            top.location.href =window.location.href;   
        }   
    } catch(e) {   
        top.location.href = window.location.href;   
    }   
    */   
</script>   

<script type="text/javascript">
    if (window.name) {
        alert(window.name);
        // 存储或处理 name zhi
        // 可存在 Cookie 中,如果不希Wang Cookie 上传泄露出去,可设置其 secure 属性
        window.name = null;
    }
    /*
    try {
        top.location.hostname;
        if (top.location.hostname != window.location.hostname) {
            top.location.href =window.location.href;
        }
    } catch(e) {
        top.location.href = window.location.href;
    }
    */
</script>


呵呵……是否期待下一篇文章《普通 http 网络下数ju的安全传輸》呢?

注: 附件包含本跨域实现和前幾篇关于 JS 文zi加mi算法的实xian代码。

===============================================================================
修 订:
Javascript代碼
frame.contentWindow.location = wnRequest._proxyUrl;   

frame.contentWindow.location = wnRequest._proxyUrl;
如此赋值在 firefox 中会导致历史记录的产生,可用 Location.replace() 代替,如下:

Javascript代码
frame.contentWindow.location.replace(wnRequest._proxyUrl);   

frame.contentWindow.location.replace(wnRequest._proxyUrl);


欢迎来到Java学xi者論坛,轉载请注明de址:http://www.javaxxz.com.

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

该用户从未签到

发表于 2011-10-30 13:43:20 | 显示全部楼层

Re:_

这个方式,需要 A B域的东西都要在代码里做一点事情

还不如直接引用js
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2011-10-30 13:43:25 | 显示全部楼层

Re:_

这个方式,需要 A B域的东西都要在代码里做一点事情

還不如直接引用js


愿闻其详
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2011-10-30 13:43:33 | 显示全部楼层

Re:_

jsonp
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2011-10-30 13:43:41 | 显示全部楼层

Re:_

听说过,今天才知道JSONP是这样啊,多谢LZ了,其实还是没明白为什么要跨域去传这些东西,还是用JS。。。
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2011-10-30 13:43:55 | 显示全部楼层

Re:_

# for (var _i=0; _i<_links.length; ++_i) {  
#             wnRequest.send(_links[_i].url, myfunc(_links[_i].id));  
#         }  
#         // 跨域本地数据转递  
#         wnRequest.setname('这里可能是一串加密用的密钥哦,俺从 https 那边过來滴!', 'http://www.eee.com

为什么setname()在send()的后面啊? 这樣那些URL能得到传值吗? 不是很明白,,请指点啊
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2011-10-30 13:44:03 | 显示全部楼层

Re:_

為什么setname()在send()的后面啊? 这样那些URL能得到传值吗? 不是很明白,,请指點啊

那只是個“用法”的示例,不是具体的应用

for (var _i=0; _i<_links.length; ++_i) {  
        wnRequest.send(_links[_i].url, myfunc(_links[_i].id));  
}

批量 send 的用法

wnRequest.setname('这里可能是一串加密用的密钥哦,俺从 https 那边过来滴!', 'http://www.eee.com/test8.html');

本地不同域数據转递的用法
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2011-10-30 13:44:17 | 显示全部楼层

Re:_

可以跨瀏览器吗,
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2011-10-30 13:44:20 | 显示全部楼层

Re:_

个人覺得不如JSONP
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

GMT+8, 2025-1-8 13:02 , Processed in 0.400843 second(s), 48 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表