跨域刷新的可行方案

来源:互联网 发布:网络新世界 编辑:程序博客网 时间:2024/05/22 02:09

基本的思路一般有两个:第一种是使用隐藏的iframe策略,它的具体依据是,我不能在当前页面上访问远程域上的脚本来刷新远程域中的页面,但是可以通过一个iframe加载一个远程中的一个页面,比如我可以通过iframe加载像百度,谷哥这样的首页页是没有有问题,这就为程序员提供了一种可能,我可以动态加载一个远程页面,由这个页面发起刷新远程其它页页的逻辑.例如可以在iframe加载的页页中放置如下代码:

<script type="text/javascript">try{//top.opener.location.reload();top.opener.refresh();//局部刷新}catch(e){//parent.close();}top.close();</script>

就可以完成刷新的逻辑,此方案已经亲自测试,是可以完成的,iframe中加载的页面可以访问与自己同域的页面中的脚本方法,以完成刷操作.在这种方案被iframe加载的页面似乎具备双重的身份,本地和远程它都沾了边,事实却并不是如此,在这个加载远程页面中如果想访问本地资源,其实它也会受到同源的策略的影响.

 

第二种方案:其实是使用了跨域的有限访问策略,例如下面的脚本在跨域时调用reload()方法是就问题,因为你不能访问location对象,但是你可以为location赋予一个地址,以达到刷新的目的

try{      window.parent.opener.location.reload();      window.parent.close();  }catch(e){          //portal为要刷新父页面的地址       window.parent.opener.location="远程地址";      window.parent.opener=null;      window.parent.close();  }  
网上的其它解决方案
1.<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">  2.<HTML>  3. <HEAD>  4.  <TITLE> New Document </TITLE>  5. </HEAD>  6. <BODY>  7.  <SCRIPT LANGUAGE="JavaScript">  8.  <!--   9.    window.onload=function(){   10.        document.getElementById("open").onclick=function(){   11.            var url="http://g.cn";   12.            var win=window.open(url);   13.            setInterval((function(win){return function(){   14.                                    if(win.closed){   15.                                        window.location.reload();   16.                                    }   17.                        };})(win),1000);       18.        }   19.    }   20.  //-->  21.  </SCRIPT>  22.  <input id="open" type="button" value="open"/>  23. </BODY>  24.</HTML>  

上面的方法采用了定时轮询子窗口的方式.

注意:使用<script>标签,这种方案一般是用来交互数据使用,想要刷新页似乎不是很可行,基本原理就是可以使用<script>标签加载一份来自远程的js文件,加载完成之后,其中脚本将会被看成本域中的资源,你可调用其中的方法,此时可以从这些方法入口参数注入远程的数据,以从本地获取远程的部分数据,一旦加载完成这份脚就应该算是本地资源,所以不能再通过此文件中的脚本再去访问远程的其它资源.所以这种方案只能用来与远程进行数据交换,而不能用此方法来控制远程的脚本.

================================================================================================

关于跨域名问题还是问题么,这方面的解决实践非常多,今天我就旧话重提把我所知道的通过几个应用场景来分别总结一下

先说明一点:我说的某某域名在您的控制下的意思是这个域名下的网页由您来负责开发内部的JavaScript
场景一:将bbs.xxx.com的页面用iframe嵌入到www.xxx.com的中,如何在iframe内外使用js通信
一级域名都是xxx.com 这个域名一定是在您的控制下,所以你只要在两个页面中同时升级域名即可
在父窗口和iframe内部分别加上js语句:document.domain="xxx.com";
之后2个页面就等于在同一域名下,通过window.parent oIframe.contentDocument就可以相互访问,进行无障碍的JS通信
在新浪、淘宝等很多页面都能找到这样的语句。不过document.domain不可以随便指定,只能向上升级,从bbs.xxx.com升级到yyy.com肯定会出错

场景二:将www.yyy.com的页面用iframe嵌入到www.xxx.com的中,两个域名都在您的控制下,如何在iframe内外进行一定的数据交流
你可以通过相互改变hash值的方式来进行一些数据的通信

这里的实现基于如下技术要点:
1、父窗口通过改变子窗口的src中的hash值把一部分信息传入,如果src只有hash部分改变,那么子窗口是不会重新载入的。
2、子窗口可以重写父窗口的location.href,但是注意这里子窗口无法读取而只能重写location.href所以要求前提是您控制两个域名,知道当前父窗口的location.href是什么并写在子窗口内,这样通过parent.location.href = "已知的父窗口的href"+"#"+hash。这样父窗口只有hash改变也不会重载。
3、上面两步分别做到了两个窗口之间的无刷新数据通知,那么下面的来说如何感知数据变化。标准中没有相关规定,所以当前的任意浏览器遇到location.hash变化都不会触发任何javaScript事件,也就是说您要自己写监听函数来监视loaction.hash的值的变化。做法是通过setTimeout或者setInterval来写一个监听函数每20-100ms查看一下hash是否变化,如果变化了驱动js根据新的数据做想做的事情。

这种实现的一些分析:
1、信息通道是双向的,当然会兼容单向,如果只是父窗口向子窗口通知数据,只需要子窗口写hash监听,反之亦然。
2、局限性也是颇大,因为这种通信的前提是双方知道对方的location.href。如果父窗口带有动态的location.search也就是查询参数,那么子窗口的处理上就比较困难,需要把父窗口的location.search作为传递信息的一部分告知子窗口。
3、另外的困扰会有浏览器带给你,IE之外的浏览器遇到hash的改变会记录历史,这样你在处理前进后退的时候会非常头疼


场景三:将www.yyy.com的页面用iframe嵌入到www.xxx.com的中,只有被嵌入的yyy.com在您的控制下,如何在iframe内外进行一定的交流
真实场景:google adsence的一个需求,你希望google发现您的页面不能匹配出相关性非常好的按点击付费广告时,你希望google的广告iframe能够隐藏。
google的广告iframe在google域下显然不能把自己隐藏掉,那么怎么办呢?
1、google会提供给你一个html页面
2、您将这个页面放置在您的域名下,并告诉google它的位置
3、当google发现没有很好的广告时,会将子窗口的loaction重定向到您的那个页面下,这样您的页面因为同域名就可以访问父页面来隐藏自己了
是不是很巧的方法?

场景四:您是内容发布商,如何改造接口,让其他域名下的页面可以从浏览器端出发获得您的数据
我们知道ajax的xmlHttpRequest()说到底是一个无刷新请求服务器数据的辅助工具,但是xmlHttpRequest并不能跨域名请求数据,在某些情况下成了极大的限制。
但是我们如果通过其他方式完成无刷新请求数据不也可以么,我们用Dom方法操作动态JS脚本请求来做这件事。
    //创建一个脚本节点
    var oScript = document.createElement('script');
    //指定脚本src src可以指向任意域名
    //注意src不再指向静态js,而是带着查询参数指向一个动态脚本广播服务。
    oScript.src = "http://yyy.com/query.php?"+yourQueryString;   
    //如果指定了charset 同时还可以解决xmlHttpRequest另一大困扰 乱码问题                                                                                                                           
    //oScript.charset = "utf-8";
    //通过Dom操作把这个新的节点加入到文档当中                                 
    document.getElementsByTagName("head")[0].appendChild(oScript);

这样只要query.php的输出是可执行的javaScript脚本,比如:djsCallBack({jsondata});
当他从服务器返回后就会自动执行,你可以方便的用json方式来做数据传递了。
要注意,您的脚本请求最好带上时间戳,避免浏览器缓存造成取回数据实时性下降。

如果您是数据提供者,您可以要求数据索取者在查询参数中提供回调函数名,比如query.php?callback=myDataHandler&key=...?
这样您就可以根据参数来提供给他myDataHandler({jsondata}),这样不同的数据索取者都会得到自定义的正确的异步回调。

进一步发展,可以做一个统一的从xml到动态json的数据转化服务器,脱离数据的实际意义,针对任何xml接口都可以作为转化后提供给客户端直接访问。
这样就不用针对单独xml数据服务,为了跨域名而做各自的后台数据抓取转化服务。

用动态脚本传数据功能非常强大,去年我最先在YAHOO的站点上看到这样的应用,让人眼前一亮。

总结总结
第一种场景,相应的处理办法有这非常好的效果,可以说完全解决了问题。
第二种场景,相应的处理办法具有一定的跨域数据交流功效,具有相当大的局限,并不适合在复杂业务流程中应用,实际上我也确实也没看到过基于此的大规模应用。
第三种场景,相应的处理办法比较巧妙,虽然redirect之后就不干你什么事了,但如果你是google一样面向众多域名的内容提供商,也是个不错的解决思路。
第四种场景,相应的处理办法非常强大,对比Ajax可以看到,跨域名没问题,无刷新没问题,本身又是异步的,JSON比xml快的多,同时解决乱码问题,只是请求都是Get方式的,不能做Post方式的请求。多一种武器自然可以从容选择了。

上面说的基本上都是从前端脚本出发的各种情景下跨域解决方案,我们还有一种新式的更强大的武器Flash,只是现在我还不会用。

原创粉丝点击