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

来源:互联网 发布:广州淘宝村 编辑:程序博客网 时间:2024/06/11 23:37
当然,“近乎完美”仅仅是个人观点,但如下所述,它确实简单而颇有效益! 

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

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

无意中看到一篇文章《使用 window.name 解决跨域问题》……豁然开朗! 俺的问题终于解决了。 

对那个实现小改了一下,加了浏览器本地设置 Window.name 的功能,实现浏览器“本地”异域数据的传递(如从浏览器窗口A传递数据到窗口B,仅在本地进行,且两个域不同)——这会产生一个很蛙王的应用(下一篇文章《普通 http 网络下数据的安全传输》将详细说明,本文后有少量提及)。感谢网络! 也感谢愿意分享的技术达人! 

下面贴出俺的代码,也分享一下,呵呵…… 
(注意:本地需要创建一个名为 proxy.html 的空文件) 

Javascript代码  收藏代码
  1. (function() {  
  2.   
  3.     var _isIE = (  
  4.         navigator.appName == "Microsoft Internet Explorer"  
  5.     );  
  6.   
  7.     var _removeNode = _isIE ? function() {  
  8.         var d;  
  9.         return function(n) {  
  10.             if(n && n.tagName != 'BODY') {  
  11.                 d = d || document.createElement('div');  
  12.                 d.appendChild(n);  
  13.                 d.innerHTML = '';  
  14.             }  
  15.         }  
  16.     }() : function(n) {  
  17.         if(n && n.parentNode && n.tagName != 'BODY') {  
  18.             n.parentNode.removeChild(n);  
  19.         }  
  20.     };  
  21.   
  22.   
  23. /* [ Request by window.name ] 
  24.  * **************************************************************************** 
  25.    借助 Window.name 实现 Js 的跨域访问。 
  26.    1、 url 向外传值, callback 处理返回结果。 
  27.    2、 返回页面中 JS 对 window.name 赋值。 
  28.  
  29.    返回页 
  30.    <script language="JavaScript"> 
  31.        window.name = ...  // 支持 JSON 字符串,可达~2MB 
  32.    </script> 
  33.  
  34.    若需同时进行多个请求,回调函数应是不同的函数实例。 
  35.    iframe 的自由载入形成了异步机制。 
  36. */  
  37.   
  38.     wnRequest = {  
  39.         _doc: document,  
  40.         _proxyUrl: 'proxy.html'  
  41.     };  
  42.   
  43.     wnRequest.send = function( url, callback )  
  44.     {  
  45.         if(! url || typeof url !== 'string') {  
  46.             return;  
  47.         }  
  48.         url += (url.indexOf('?') > 0 ? '&' : '?') + 'windowname=get';  
  49.   
  50.         var frame = this._doc.createElement('iframe');  
  51.         frame._state = 0;  
  52.         this._doc.body.appendChild(frame);  
  53.         frame.style.display = 'none';  
  54.   
  55.         (function( el, type, fn ) {  
  56.             if (_isIE) {  
  57.                 el.attachEvent('on' + type, fn);  
  58.             } else {  
  59.                 el.addEventListener(type, fn, false);  
  60.             }  
  61.         })(frame, 'load'function() {  
  62.             if(frame._state == 1) {  
  63.                 _getData(frame, callback);  
  64.             } else if(frame._state == 0) {  
  65.                 frame._state = 1;  
  66.                 //frame.contentWindow.location = wnRequest._proxyUrl;  
  67.                 frame.contentWindow.location.replace(wnRequest._proxyUrl);  
  68.             }  
  69.         });  
  70.         frame.src = url;  
  71.     };  
  72.   
  73.     //  
  74.     // 设置异域 Js 可访问的本地数据,客户端直接站间转递数据  
  75.     // 注:  
  76.     // 即浏览器直接将数据转递给另一个域的窗口,数据不上网。  
  77.     // 返回页代码:  
  78.     // <script type="text/javascript">  
  79.     //     if (window.name) {  
  80.     //         //... 处理 name 值  
  81.     //         window.name = null;  
  82.     //     }  
  83.     //     // 升为顶级窗口,完成数据转递  
  84.     //     try {  
  85.     //         top.location.hostname;  
  86.     //         if (top.location.hostname != window.location.hostname) {  
  87.     //             top.location.href =window.location.href;  
  88.     //         }  
  89.     //     } catch(e) {  
  90.     //         top.location.href = window.location.href;  
  91.     //     }  
  92.     // </script>  
  93.     //  
  94.     //  
  95.     wnRequest.setname = function( name, url ) {  
  96.         if(! url || typeof url !== 'string') {  
  97.             return;  
  98.         }  
  99.         url += (url.indexOf('?') > 0 ? '&' : '?') + 'windowname=loc';  
  100.   
  101.         var frame = this._doc.createElement('iframe');  
  102.         frame._count = 0;  
  103.         this._doc.body.appendChild(frame);  
  104.         frame.style.display = 'none';  
  105.         if (_isIE) {  
  106.             frame.name = name;  
  107.         } else {  
  108.             frame.contentWindow.name = name;  
  109.         }  
  110.         frame.src = url;  
  111.     };  
  112.   
  113.     //  
  114.     // 私用辅助  
  115.     //  
  116.     var _clear = function(frame) {  
  117.         try {  
  118.             frame.contentWindow.document.write('');  
  119.             frame.contentWindow.close();  
  120.             _removeNode(frame);  
  121.         } catch(e) {}  
  122.     }  
  123.   
  124.     var _getData = function(frame, callback) {  
  125.         try {  
  126.             var da = frame.contentWindow.name;  
  127.         } catch(e) {}  
  128.         _clear(frame);  
  129.         if(callback && typeof callback === 'function') {  
  130.             callback(da);  
  131.         }  
  132.     }  
  133.   
  134. })();  


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

Javascript代码  收藏代码
  1. <script language="javascript">  
  2.     var _str = '', _cnt = 0;  
  3.   
  4.     function myfunc( id ) {  
  5.         return  function( data ) {  
  6.             _str += id + ':' + data + '\n';  
  7.             ++_cnt;  
  8.             if (_cnt >= 4)  alert(_str);  
  9.         };  
  10.     }  
  11.   
  12.     var _links = [  
  13.         { id: 4, url: 'http://www.aaa.com/test4.html' },  
  14.         { id: 5, url: 'http://www.bbb.com/test5.html' },  
  15.         { id: 6, url: 'http://www.ccc.com/test6.html' },  
  16.         { id: 7, url: 'http://www.ddd.com/test7.html' }  
  17.     ];  
  18.     function dosome() {  
  19.         for (var _i=0; _i<_links.length; ++_i) {  
  20.             wnRequest.send(_links[_i].url, myfunc(_links[_i].id));  
  21.         }  
  22.         // 跨域本地数据转递  
  23.         wnRequest.setname('这里可能是一串加密用的密钥哦,俺从 https 那边过来滴!''http://www.eee.com/test8.html');  
  24.     }  
  25. </script>  


http://www.aaa.com/test4.html 中的内容:(跨域网络数据传递) 

Javascript代码  收藏代码
  1. <script type="text/javascript">  
  2.     window.name='返回的数据,可以是 JSON 格式';  
  3. </script>  


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

Javascript代码  收藏代码
  1. <script type="text/javascript">  
  2.     if (window.name) {  
  3.         alert(window.name);  
  4.         // 存储或处理 name 值  
  5.         // 可存在 Cookie 中,如果不希望 Cookie 上传泄露出去,可设置其 secure 属性  
  6.         window.name = null;  
  7.     }  
  8.     /* 
  9.     try { 
  10.         top.location.hostname; 
  11.         if (top.location.hostname != window.location.hostname) { 
  12.             top.location.href =window.location.href; 
  13.         } 
  14.     } catch(e) { 
  15.         top.location.href = window.location.href; 
  16.     } 
  17.     */  
  18. </script>  


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

注: 附件包含本跨域实现和前几篇关于 JS 文字加密算法的实现代码。 

=============================================================================== 
修 订: 
Javascript代码  收藏代码
  1. frame.contentWindow.location = wnRequest._proxyUrl;  

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

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

  • xtools.rar (5.4 KB)
  • 下载次数: 1264
原文地址
0 0
原创粉丝点击