yjanboo’s logs | 低处生活

Asking costs nothing.

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

方案一、剪贴板

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

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

演示:[ 点此阅览 ]

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

  1. <script type=text/javascript>
  2. var ua = navigator.userAgent;
  3. if ((i = ua.indexOf(MSIE)) >= 0)
  4. {
  5. var iObjH = window.document.documentElement.scrollHeight;
  6. window.clipboardData.setData(text,String(iObjH));
  7. }
  8. </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也可以实现跨域,只是还没去实践,实践完了再补充。啥时候能补完呢?恩……

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

  • 30 views
  • Comments Off
  • 推荐文章:《工作以后十不要》佚名

    • 星期一 三 9,2009 04:44 下午
    • By yjanboo
    • In living


    与君共勉,希望大家和自己能够注意,细节决定成败。


    Read the rest of this entry »

  • 15 views
  • Comments Off
  • ubuntu Myeclipse7 installtion…

    • 星期四 二 26,2009 05:55 下午
    • By admin
    • In 潮物推介

    I got a Myeclipse7, a ISO file.

    So let’s begin to install it.

    1. Make sure you use a sun jdk. besacuse a openjdk may not support or even lead some error.

    sudo update-alternatives ——config java
    you will get this:
    选择        可选项
    ———————————————–
    1    /usr/bin/gij-4.2
    2    /usr/bin/gij-4.3
    3    /usr/lib/jvm/java-gcj/jre/bin/java
    +        4    /usr/lib/jvm/java-6-openjdk/jre/bin/java
    *         5    /usr/lib/jvm/java-6-sun/jre/bin/java

    要维持缺省值[*],按回车键,或者键入选择的编号:
    choice a sun jdk more than version 5, if there is no sun-jdk ,use apt-get to install one.

    2 mount the ISO file.

    sudo mkdir /media/me
    sudo mount -o loop myeclipse7.iso /media/me

    3 install it.

    cd /media/me
    ./myeclipse-70-installer.

    the first setp is very important, remeber it! That’s ALL.

  • 213 views
  • 1 Comment
  • 尚未整理的links

    • 星期二 二 24,2009 07:16 下午
    • By admin
    • In 潮物推介

    Linux C 编程一站式学习
    http://learn.akae.cn/media/index.html
    最近正好在学linux。很有必要看看。

  • 3 views
  • 0 Comments
  • MapReduce: A major step backwards

    http://www.databasecolumn.com/2008/01/mapreduce-a-major-step-back.html

    By David DeWitt on January 17, 2008 4:20 PM
    [Note: Although the system attributes this post to a single author, it was written by David J. DeWitt and Michael Stonebraker]

    Read the rest of this entry »

  • 302 views
  • 604 Comments
  • Pages (6): « 1 2 3 4 5 » ... Last »

    倒计时:)

    • 2010YBD: 170 日 18 时 3 分 35 秒 之前

    天气预报

    friends

    标签

    Series

    RSS Feeds

    Ads Here