`

来谈谈”完美”跨域

阅读更多

原文:http://ued.alipay.com/?p=707     觉得说得很全面,记录一下

 

 

关于跨域这个话题,很早就答应过要分享,但是因为懒,一直拖着,直到D2上有人谈起了“完美跨域”。“跨域”应该已经算不上什么难题了,只是提起“ 完美”这两个字,突然觉得有了新意,那就写点什么吧,至少对自己有个交代嘛!跨域方案有很多,接下来一一枚举,会给出demo,demo的宗旨是尽可能简 单的让新手明白,各方案中跨域的原理,实际应用请酌情修改。

方案一、剪贴板

原理: IE本身依附于windows平台的特性为我们提供了一种基于iframe,利用内存来“绕行”的方案,在这里我称之为,本地存储原理。

缺点: 不支持非IE浏览器,并且影响到用户对剪贴板的操作,用户体验非常不好,特别是在IE7下,受安全等级影响,会弹出提示框。

演示: [ 点此阅览 ]

子页面在子域:demo.ioldfish.cn 下,在页面中加入如下代码获取页面高度并存入剪贴板。

  <script type="text/javascript">
   var ua = navigator.userAgent;
   if ((i = ua.indexOf("MSIE")) >= 0) 
   {
    var iObjH = window.document.documentElement.scrollHeight;
    window.clipboardData.setData('text',String(iObjH));
   }
  </script>
 

主页面在主域:www.ioldfish.cn 下,在页面中加入如下代码,获取剪贴板的值并赋值为子页面所在的iframe的高度。

  1. < script type = " text/javascript " >
  2. window . onload = function ()
  3. {
  4.   var iObj = document . getElementById ( ' iId ' ) ;
  5.   iObj . style . height = parseInt ( window . clipboardData . getData ( ' text ' )) + ' px ' ;
  6. }
  7. < / script>

 

方案二、document.domain

原理: 设置了document.domain,欺骗浏览器

缺点: 无法实现不同主域之间的通讯。并且当在一个页面中还包含有其它的iframe时,会产生安全性异常,拒绝访问。

演示: [ 点此阅览 ]

主页面在主域:www.ioldfish.cn 下,子页面在子域:demo.ioldfish.cn 下,在两个页面的头部都加入如下代码:

  1. < script type = " text/javascript " >
  2.   document . domain = " ioldfish.cn " ;
  3. < / script>

方案三、通过JS获取hash值实现通讯

原理: hash可以实现跨域传值实现跨域通讯。

缺点: 对于父窗口URL参数动态生成的,处理过程比较复杂一些。并且IE之外的浏览器遇到hash的改变会记录历史,影响浏览器的前进后退功能,体验不佳。

演示: [ 点此阅览 ]

子页面在主域:www.lzdaily.com 下,在页面中添加如下代码,因为hash是不受跨域限制的,所以可以将本页面的高度顺利的传送给主页面的hash。

  1. < script type = " text/javascript " >
  2.   var hashH = document . documentElement . scrollHeight ;
  3.   var urlA = " http://www.ioldfish.cn/wp-content/demo/domain/hash/a2.html " ;
  4.   parent . location . href = urlA + " # " + hashH ;
  5. < / script>

主页面在主域:www.ioldfish.cn 下,在页面中添加如下代码,首先取得子页面传递过来的hash值,然后将hash值赋到子页面所在的iframe的高度上。

  1. < script type = " text/javascript " >
  2. window . onload = function ()
  3. {
  4.   var iObj = document . getElementById ( ' iId ' ) ;
  5.   if ( location . hash )
  6.   {
  7.   iObj . style . height = location . hash . split ( " # " )[ 1 ] + " px " ;
  8.   }
  9. }
  10. < / script>

方案四、传hash值实现通讯改良版

原理: 该方案通过“前端代理”的方式,实现hash的传值,体验上比之方案三有了很大的提升。

缺点: 对于父窗口URL参数动态生成的,处理过程比较复杂一些。

演示: [ 点此阅览 ]

子页面在主域:www.lzdaily.com 下,在页面中添加如下代码,首先在页面里添加一个和主页面同域的iframe[也可动态生成],他的作用就像是个跳板。C页面中不需任何代码,只要确保有个页面就防止404错误就可以了!该方法通过修改iframe的name值同样可以跨域传值,只是比较”猥琐“而已。

  1. < iframe id = " iframeC " name = " iframeC " src = " http://www.ioldfish.cn/wp-content/demo/domain/hashbetter/c.html " frameborder = " 0 " height = " 0 " ></ iframe >

然后在页面中加上如下代码,利用页面C的URL接收hash值,并负责把hash值传给同域下的主页面。

  1. < script type = " text/javascript " >
  2.   hashH = document . documentElement . scrollHeight ;
  3.   urlC = " http://www.ioldfish.cn/wp-content/demo/domain/hashbetter/c.html " ;
  4.   document . getElementById ( " iframeC " ) . src = urlC + " # " + hashH ;
  5. < / script>

主页面在主域:www.ioldfish.cn 下,在页面中添加如下代码,获取从C页面中传递过来的hash值。这里应用到一个技巧,就是直接从A页面用frames["iId"].frames["iframeC"].location.hash ,可以直接访问并获取C页面的hash值。这样一来,通过代理页面传递hash值,比起方案三,大大提高了用户体验。

  1. < script type = " text/javascript " >
  2. window . onload = function ()
  3. {
  4.   var iObj = document . getElementById ( ' iId ' ) ;
  5.   iObjH = frames [ " iId " ] . frames [ " iframeC " ] . location . hash ;
  6.   iObj . style . height = iObjH . split ( " # " )[ 1 ] + " px " ;
  7. }
  8. < / script>

方案五、JSONP

原理: 有点脚本注入的味道

缺点: 服务器端程序运行比脚本早,跨域交互时无法捕获前端页面元素的相关数据,比如自适应高度。

演示: [ 点此阅览 ]

主页面在主域:www.ioldfish.cn 下,在页面中添加如下代码,动态创建一个script,然后指定到子域的动态文件,在动态文件后面可以添加参数,在这里我加了一个回调函数,当请求返回后,会运行这个回调函数。

  1. < script type = " text/javascript " >
  2. function   loadContent ()
  3. {
  4.   var scriptDom = document . createElement ( ' script ' ) ;
  5.   var url = " http://www.lzdaily.com/domain/jsonp/Test.aspx?f=setDivContent' " ;
  6.   scriptDom . src = url ;
  7.   document . body . appendChild ( scriptDom ) ;
  8. }  
  9. function   setDivContent ( love )
  10. {
  11.   var fishDiv = document . getElementById ( " oldFish " ) ;
  12.   fishDiv . innerHTML = love ;
  13. }
  14. < / script>

子页面在主域:www.lzdaily.com 下,在页面中添加如下代码,首先先取得主页面传过来的回调函数名,然后生成一段 javascript代码,以回调函数带参数的形式返回主页面,这样就完成了跨域之间的通讯。由于服务器端程序执行总是优先于javascript代码, 所以基本上没办法获取到子页面中DOM的相关数据,所以小白同学,我可以很负责人的告诉你,想通过这种方法实现跨域自适应高度是不可能的!

  1. < script language = " C# " runat = " server " >
  2. void   Page_Load ( object sender , EventArgs e )
  3. {
  4.   string   f = Request . QueryString [ " f " ] ;
  5.   Response . Clear () ;
  6.   Response . ContentType = " application/x-javascript " ;
  7.   Response . Write ( String . Format ( @ " {0}({1}); " , f , 1122 )) ;
  8.   Response . End () ;
  9. }
  10. < / script>

方案六、window.name

原理: window.name本身并不能实现跨域,只是中间做了代理。

缺点: 获取异域的前端页面元素值有一定局限性,比如取自适应高度的值。但是此方法在前端页面元素的数据交互上明显比JSONP强。

演示: [ 点此阅览 ]

这个方案,YAHOO的同事已经给出了详细的demo,我就不重复了,演示demo出自YAHOO克军 之手。详细的说明可以参看“怿飞的BLOG” ,个人觉得方案四比window.name适用面更广一些。

方案七、window.navigator

原理: window.navigator这个对象是在所有的Iframe中均可以访问的对象。应该是IE的一个漏洞!

缺点: 不支持IE外的浏览器下的跨域。严格的dtd申明后,该方法失效!

演示: [ 点此阅览 ]

主页面在主域:www.ioldfish.cn 下,首先先申明一个Json用来保存所有页面的高度window.navigator.PagesHeight={”":0}; ,然后根据name的属性找到页面的数据window.navigator.getData ,最后将页面的数据注册到window.navigator.PagesHeight 中。这里还定义了一个函数resetIframeData ,在页面加载的时候调用它,完成跨域的数据交互。注释中详细说明了参数的作用。

  1. < script type = " text/javascript " >
  2. window . navigator . PagesHeight = { "" : 0 } ;   
  3. window . navigator . getData = function ( pageName )   {      
  4.   return window . navigator . PagesHeight [ pageName ] ;  
  5. } ;   
  6. window . navigator . putData = function ( pageName , pageHeight )  
  7. {   
  8.   window . navigator . PagesHeight [ pageName ] = pageHeight ;  
  9. } ;
  1. /*
  2. *iframeId:页面中iframe的标识id
  3. *key:子页面自定义的json标识,这里就是子页面定义的"PortalData".
  4. *defaultData:无法取到值时候调用
  5. */
  6. function   resetIframeData ( iframeId , key , defualtData )
  7. {        
  8.   var obj = document . getElementById ( iframeId ) ;  
  9.   if ( window . navigator . getData )
  10.   {   
  11.   var   pageHeight = window . navigator . getData ( key )
  12.   if ( pageHeight && String ( pageHeight ) . match ( / \d+ / ))
  13.   {   
  14.    obj . style . height = pageHeight + ' px ' ;  
  15.   }
  16.   else
  17.   {   
  18.    obj . style . height = defualtData + ' px ' ;  
  19.   }   
  20.   }
  21.   else
  22.   {   
  23.   obj . style . height = defualtData + ' px ' ;  
  24.   }      
  25. }  
  26. < / script>

子页面在主域:www.lzdaily.com 下,获取到页面高度后,将高度存到主页定义的Json中,Json标识为”PortalData”,这里可以自定义。

  1. < script type = " text/javascript " >
  2. window . onload = function   getPageData ()
  3. {          
  4.   var pageHeight = document . body . scrollHeight ;  
  5.   if ( window . navigator . putData )
  6.   {
  7.   window . navigator . putData ( " PortalData " , pageHeight ) ;
  8.   }
  9. }  
  10. < / script>

其实通过css也可以实现跨域,数据获取的实质其实就是动态载入一段CSS,然后解析其中的字段提取数据,这个方法比较“猥琐”,再这里就不多介绍了,当然flash也可以实现跨域,只是还没去实践,实践完了再补充。啥时候能补完呢?恩……

以上这么多方案,有可以“完美跨域”的吗?单一的看,我想没有吧,都有缺陷,但是只要不同情况下使用合适的方法,我想这才是最完美的!原来绕了一圈,我只是再说废话,哎!不论怎么样,还是希望这些废话对还在苦苦追求“完美”的同学们有所启发!

Tags: jsonp , window.name , window.navigator , 跨域

星期三, 12月 17th, 2008

<!-- at 12:04-->

前端技术 .

分享到:
评论

相关推荐

    完美解决iframe跨域问题

    本文将深入探讨如何“完美解决iframe跨域问题”,并介绍其底层的`window.name`转换代理实现。 **一、iframe跨域的基本概念** 1. **什么是iframe**:iframe是一种HTML元素,允许在单个网页中嵌入另一个网页。它通过...

    pdf.js 跨域版本

    总的来说,这个"pdf.js 跨域版本"为开发者提供了更便捷的方式来在 Web 页面上展示 PDF 文件,尤其是对于包含中文字符的文档,它提供了更好的兼容性和显示效果。如果你在实际应用中遇到任何问题,可以参考 PDF.js 的...

    完美解决跨域iframe的高度自适应

    完美解决跨域iframe的高度自适应,完美解决跨子域iframe的高度自适应,嵌入几个页面解决跨域iframe的高度自适应。。。

    Vue中跨域及打包部署到nginx跨域设置方法

    一般来讲,前后端分离的项目在大公司都会由后台设置允许跨域访问,因为后台设置允许跨域是很简单和方便的,但是某些情况下,一些小公司或者你工作的场所后台不怎么配合的情况下,这就需要前端来配置跨域请求来方便我们...

    H5的video标签跨域.HTML的video标签跨域_跨域ajax

    H5的video标签跨域.HTML的video标签跨域 我们都知道HTML video标签能播放视频 但是如果你的video要播放的是非当前域名下的视频文件,这就要跨域播放视频, 应该如何实现呢?

    MVC中跨域解决方案

    总结来说,MVC中处理跨域问题主要依赖于CORS机制,通过配置中间件、过滤器或Web.config文件来允许特定的源进行跨域访问。同时,也可以考虑JSONP、后端代理等其他解决方案。在实际项目中,应根据安全性和需求选择合适...

    js跨域解决方案

    理解并掌握这些跨域解决方案对于JavaScript开发者来说至关重要,因为它们可以帮助我们在构建复杂Web应用时克服浏览器的同源策略限制,实现更丰富的功能。在实际项目中,应根据需求选择最适合的跨域策略,确保安全性...

    finereport跨域打印文档

    在进行跨域打印时,可能会遇到浏览器的安全策略限制,这需要开发者通过特定的技术手段来实现跨域访问和打印功能。 1. **同源策略**:同源策略是浏览器为了保障用户信息安全而设定的一种安全机制,它规定JavaScript...

    ArcGIS Server 10.2跨域jar包

    在这个场景中,我们关注的是"跨域jar包",这涉及到网络应用中的跨域资源共享(CORS)策略。 跨域是Web应用程序的基本安全机制,它防止了一个源(如浏览器中的JavaScript)访问另一个源(如不同域名的服务器)的数据...

    跨域安全JAR包

    总的来说,跨域安全JAR包提供了一种便捷、安全的跨域解决方案,减少了开发者处理跨域问题的复杂性,提高了Web应用的可交互性和安全性。通过合理使用并配置此JAR包,开发者可以更加专注于业务逻辑,而非基础的跨域...

    完美解决跨域问题和静态资源冲突的demo(png图片)

    sprigboot 完美解决跨域问题和静态资源冲突的demo: final static org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CorsFilter.class); public void doFilter(ServletRequest req, ServletResponse ...

    Cesium加载Geoserver跨域问题

    除了上述方法,还可以在Cesium的客户端代码中使用JSONP(JSON with Padding)或者代理服务器来绕过跨域限制,但这通常需要更多的开发工作。 总结一下,解决Cesium加载Geoserver跨域问题的关键在于正确配置Geoserver...

    umi_UMI_umi跨域401_umi跨域_Umi跨域打包_umi脚手架_

    umi使用的是webpack进行打包,我们可以在配置文件`config/config.js`或`config/umi.js`中添加相应的webpack配置,例如设置`proxy`或修改`output.publicPath`来适应部署环境的跨域需求。同时,umi还支持通过`@umijs/...

    Jquery跨域Ajax请求测试

    jQuery,作为一个强大的JavaScript库,提供了便捷的方式来处理这种问题,特别是通过其Ajax功能进行跨域请求。本示例"Jquery跨域Ajax请求测试"将详细讲解如何利用jQuery实现这一功能。 首先,了解同源策略是理解跨域...

    jquery跨域调用 js跨域调用

    jQuery作为一款广泛使用的JavaScript库,提供了方便的API来处理这种限制,实现跨域调用。 一、什么是jQuery跨域调用? jQuery跨域调用主要是通过JSONP(JSON with Padding)和CORS(Cross-Origin Resource Sharing...

    Tomcat配置解决跨域问题

    这意味着我们可以通过修改Tomcat的配置来允许特定的跨域请求。这个压缩包包含了解决这个问题的详细步骤,只要按照指导操作,就能确保跨域请求能够成功执行。 以下是解决Tomcat跨域问题的详细步骤: 1. **添加CORS ...

    tomcat跨域解决方案

    为了解决Tomcat在IP和端口不同时引发的跨域问题,可以通过编写并配置`crossDomain.xml`文件来实现跨域支持。下面将详细介绍几种常见的配置方式: ##### 1. 允许特定域名访问 在某些情况下,可能只需要允许来自特定...

    cesium跨域加载问题

    在Tomcat服务器上配置跨域,我们可以通过修改`web.xml`文件来实现。打开`conf/web.xml`,找到`&lt;web-app&gt;`标签,在其内部添加以下`&lt;filter&gt;`和`&lt;filter-mapping&gt;`配置: ```xml &lt;filter-name&gt;CorsFilter ...

    arcgis跨域.rar

    2. **jsonp(JSON with Padding)**:JSONP是一种早期的跨域解决方案,通过动态创建`&lt;script&gt;`标签来请求资源。ArcGIS JavaScript API支持JSONP,通过设置请求参数`callback`来实现。服务器端需要相应地返回一个...

Global site tag (gtag.js) - Google Analytics