本文转自:http://www.cnblogs.com/qixuejia/archive/2012/08/29/2662220.html

javascript跨域有两种情况:

1、基于同一父域的子域之间,如:a.c.com和b.c.com

2、基于不同的父域之间,如:www.a.com和www.b.com

3、端口的不同,如:www.a.com:8080www.a.com:8088

4、协议不同,如:http://www.a.com和https://www.a.com

对于情况3和4,需要通过后台proxy来解决,具体方式如下:

a、在发起方的域下创建proxy程序

b、发起方的js调用本域下的proxy程序

c、proxy将请求发送给接收方并获取相应数据

d、proxy将获得的数据返回给发起方的js

发起方页面代码如下:

<form id="form1" runat="server">
    <div>               
        <input type="text" id="txtSrc" value="http://www.gzsums.edu.cn/webclass/html/html_design.html" style="width: 378px" />
        <input id="btnProxy" type="button" value="通过Proxy获取数据" onclick="GetDataFromProxy();" /><br />
        <br />
        <br />
    </div>
   <div id="divData"></div>
</form>
</body>
<script language="javascript"  type="text/javascript">      
   function GetDataFromProxy() {
       var src = document.getElementById('txtSrc').value;
       var request = null;
       if (window.XMLHttpRequest) {
           request = new XMLHttpRequest();
       }
       else if (window.ActiveXObject) {
           request = new ActiveXObject("Microsoft.XMLHTTP");
       }

request.onreadystatechange = function() {
           var ready = request.readyState;
           var data = null;
           {
               if (ready == 4) {
                   data = request.responseText;
                   document.getElementById('divData').innerHTML = data;
               }
               else {
                   document.getElementById('divData').text = "Loading";
               }
           }
       }

var url = "Proxy.ashx?src=" + escape(src);       
       request.open("get",url,false);
       request.send(null);
   }    
</script>

发起方Proxy代码如下:

using System.Data;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;
using System.IO;
using System.Net;
using System.Text;

namespace WebApplication1
{
    /// <summary>
    /// Summary description for $codebehindclassname$
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class Proxy : IHttpHandler
    {
        const int BUFFER_SIZE = 8 * 1024;
        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";
            string src = context.Request["src"];

WebRequest wr = WebRequest.Create(src);
            WebResponse wres = wr.GetResponse();
            Encoding resEncoding = System.Text.Encoding.GetEncoding("gb2312");
            StreamReader sr = new StreamReader(wres.GetResponseStream(), resEncoding);
            string html = sr.ReadToEnd();
            sr.Close();
            wres.Close();

context.Response.Write("<br/><br/><br/><br/>");
            context.Response.Write(html);
        }

public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

而情况1和2除了通过后台proxy这种方式外,还可以有7种办法来解决:

1、document.domain+iframe(只能解决情况1):

a、在发起方页面和接收方页面设置document.domain,并将值设为父域的主域名(window.location.hostname)

  b、在发起方页面创建一个隐藏的iframe,iframe的源是接收方页面

c、根据浏览器的不同,通过iframe.contentDocument || iframe.contentWindow.document来获得接收方页面的内容

d、通过获得的接收方页面的内容来与接收方进行交互

这种方法有个缺点,就是当一个域被攻击时,另一个域会有安全漏洞出现。

发起方页面代码如下:

<body>
<div>               
    <input type="text" id="txtSrc" value="http://b.a.com/DomainTest2.htm" style="width: 378px" />
    <input id="btnDomain" type="button" value="通过Domain获取数据" onclick="GetDataFromDomain();" /><br />
    <br />
    <br />
</div>
<div id="divData"></div>
</body>
<script language="javascript"  type="text/javascript">
    document.domain = 'a.com';
    var src = document.getElementById('txtSrc').value;
    var ifr = document.createElement('iframe');
    ifr.src = src;
    ifr.style.display = 'none';
    document.body.appendChild(ifr);
    function GetDataFromDomain() {
        var doc = ifr.contentDocument || ifr.contentWindow.document;
        alert(doc.getElementById("data").value);
    }
</script>

接收方页面代码如下:

<body>
    <input type="hidden" id="data" value="Cross Domain" style="width: 378px" />
</body>
<script language="javascript"  type="text/javascript">
    document.domain = 'a.com';   
</script>

2、动态创建script:

  a、在发起方页面动态加载一个script,script的URL指向接收方的一个处理地址(后台),该地址返回的javascript方法会被执行,另外URL中可以传入一些参数,该方法只支持GET方式提交参数。

  b、加载的script可以在调用跨域js方法后再做一些自己的处理

发起方页面的代码如下:

<head>
    <title>Script Test</title>
    <script language="javascript" type="text/javascript">
    function load_script(callback){  
        var head = document.getElementsByTagName('head')[0];
        var script = document.createElement('script');
        var src = document.getElementById('txtSrc').value;
        script.type = 'text/javascript';  
        script.src = src;  
        //借鉴了jQuery的script跨域方法  
        script.onload = script.onreadystatechange = function(){  
            if((!this.readyState||this.readyState === "loaded"||this.readyState === "complete")){  
                callback && callback();  
                // Handle memory leak in IE  
                script.onload = script.onreadystatechange = null;  
                if ( head && script.parentNode ) {  
                  head.removeChild( script );  
                }  
            }  
        };  
        // Use insertBefore instead of appendChild  to circumvent an IE6 bug.  
        head.insertBefore( script, head.firstChild );
    }   
    </script>
</head>
<body>
<input type="text" id="txtSrc" value="http://www.b.com/scripttest.aspx" style="width: 378px" />
<input type="button" value="通过动态创建script标签来获取数据" onclick="load_script(function(){alert('动态加载script标签成功')})"/>
</body>

接收方服务器端代码如下:

protected void Page_Load(object sender, EventArgs e)
{           
            Response.Clear();
            Response.ContentType = "application/x-javascript";
            Response.Write(String.Format(@"alert('{0}');", DateTime.Now));
            Response.End();
}

3、location.hash+iframe:

  a、发起方创建一个隐藏的iframe,iframe的源指向接收方的页面,并通过接收方页面的hash值来传送数据

  b、发起方创建一个定时器,定时检查自己的location.hash并作相应的处理

c、接收方创建一个隐藏的iframe,iframe的源指向发起方所在域的一个代理页面,并将接收方根据发起方传入的数据而处理后的数据通过代理页面的hash值来传送

d、接收方创建一个定时器,定时检查自己的location.hash并作相应的处理

e、代理页面创建一个定时器,定时检查自己的location.hash并同步更新发起方页面的hash值

www.a.com/a.html#aaa,其中#aaa就是location.hash值

发起方页面代码如下:

<body>
<div>
<input type="text" id="txtSrc" value="1" style="width: 378px" />
<input id="btnAddHash" type="button" value="添加Hash值" onclick="addHash();" />
<iframe id="ifr1" style="display:none"></iframe>
</div>
</body>
<script language="javascript"  type="text/javascript">
    function addHash() {
        var src = document.getElementById('txtSrc').value;
        if (src.length > 0) {           
            changeHash(src);
        }
    }
    function changeHash(src) {
        if (document.getElementById('ifr1')) {
            var ifr = document.getElementById('ifr1');
            ifr.src = 'http://www.b.com/Test/HashTest2.htm#' + src;
        }
        else {
            var ifr = document.createElement('iframe');
            ifr.setAttribute('id', 'ifr1');
            ifr.src = 'http://www.b.com/Test/HashTest2.htm#' + src;
            ifr.style.display = 'none';
            document.body.appendChild(ifr);
        }
    }
    function checkHash() {
        if (location.hash && location.hash.length > 1) {
            changeHash(location.hash.substring(1));
        }
    }
    setInterval(checkHash, 2000);
</script>

接收方页面代码如下:

<body>
<iframe id="ifr2" style="display:none"></iframe>
</body>
<script language="javascript"  type="text/javascript">   
    function checkHash() {
        if (location.hash && location.hash.length > 1) {
            var hashData = location.hash.substring(1);
            var ifr = null;
            if (document.getElementById('ifr2')) {
                ifr = document.getElementById('ifr2');               
            }
            else {
                ifr = document.createElement('iframe');
                ifr.setAttribute('id', 'ifr2');               
                ifr.style.display = 'none';
                document.body.appendChild(ifr);
            }
            switch (hashData) {
                case '1':
                    alert('One');
                    if (ifr) {
                        ifr.src = 'http://www.a.com/test/HashTest3.htm#2';
                    }
                    break;
                case '2':
                    alert('Two');
                    if (ifr) {
                        ifr.src = 'http://www.a.com/test/HashTest3.htm#1';
                    }
                    break;
                default:
                    break;
            }
        }
    }
    setInterval(checkHash, 2000);
</script>

发起方域下的代理页面代码如下:

<body></body>
<script language="javascript" type="text/javascript">
    function checkHash() {       
        if (parent && parent.parent && parent.parent.location && self.location.hash.length > 1) {
            parent.parent.location.hash = self.location.hash.substring(1);
        }
    }
    setInterval(checkHash, 500);
</script>

4、window.name:

a、发起方页面创建一个隐藏的iframe,并且源指向接收方页面

b、接收方在自己页面通过script将需要传送的数据放入window.name里

c、发起方在iframe的onload方法里将iframe的源改为和自己在同一个域下的代理页面(因为只能是同一个域下才能访问window.name的值)

d、获取window.name的值(虽然iframe的源改变了,但是window.name的值不会变)

window.name的值差不多可以有2MB大小

发起方页面代码如下:

<body>
<div>
<input id="btnName" type="button" value="通过window.name获取数据" onclick="getData();" />
<iframe id="ifr1" style="display:none" src="http://www.b.com/Test/NameTest2.htm"></iframe>
</div>
</body>
<script language="javascript"  type="text/javascript">
    var ischanged = false;
    function changeSrc() {
        if (document.getElementById('ifr1')) {
            var ifr = document.getElementById('ifr1');
            if (!ischanged) {
                ischanged = true;
                ifr.contentWindow.location = 'http://www.a.com/Test/NameTest3.htm';
            }
            else {
                var data = ifr.contentWindow.name;
                alert(data);
            }
        }
        else {
            var ifr = document.createElement('iframe');
            ifr.setAttribute('id', 'ifr1');
            ifr.src = 'http://www.b.com/Test/NameTest2.htm';
            ifr.style.display = 'none';
            document.body.appendChild(ifr);
        }
    }
    function getData() {
        setInterval(changeSrc, 2000);
    }
</script>

接收方页面代码如下:

<body></body>
<script language="javascript"  type="text/javascript">
    window.name = 'NameTest2';
</script>

发起方域下的代理页面代码如下:

<body></body>

(其实什么都不用写)

5、HTML5的postMessage

    a、receiverWindow.postMessage(msg, targetOrigin),receiverWindow就是对接收消息的window的引用,可以是iframe的contentWindow/window.open的返回值/window.frames中的一个;msg就是要发送的消息,string类型;targetOrigin用于限制receiverWindow的URI,包括主域名和端口,使用“*”表示无限制,但是为了安全起见还是需要设置下,以防把消息发送给恶意的网站,如果targetOrigin的URI和receiverWindow的不符,则放弃发送消息。
    b、接收方通过message事件来获得消息,并且通过event.origin的属性来验证发送方并通过event.data来获得传送的消息内容,event.source来获得发送方的window对象
发起方页面代码如下:
<body>
<div>
<input id="btnPostMessage" type="button" value="通过PostMessage获取数据" onclick="getData();" />
<iframe id="ifr" style="display:none" src="http://www.b.com/Test/PostMessageTest2.htm"></iframe>
</div>
</body>
<script language="javascript" type="text/javascript">
    function getData() {
        var ifr = document.getElementById('ifr');
        var targetOrigin = 'http://www.b.com';
        if (ifr.contentWindow.postMessage) {
            ifr.contentWindow.postMessage('PostMessageTest2', targetOrigin);
        }
    }
</script>
接收方页面代码如下:

<body></body>
<script language="javascript" type="text/javascript">
    window.addEventListener('message', function(event) {
        if (event.origin == 'http://www.a.com') {
            alert(event.data);   
            alert(event.source);   
        }
    }, false);
</script>

6、window.opener(适用于IE6、7,也就是operner hack方法,不过貌似现在已经不管用了,只要打过微软的安全补丁.kb2497640就不能用了)

  a、发起方页面创建一个隐藏的iframe,并且源指向接收方页面

b、发起方页面通过iframe.contentWindow.opener = {a: function(params){...}, b: function(params){...} ...}来定义可被接收方调用的方法

c、接收方页面通过window.opener.a/window.opener.b来调用发起方定义的方法

d、接收方页面通过parent.opener = {c: function(params){...}, d: function(params){...} ...}来定义可被发起方调用的方法

e、发起方页面通过opener.c/opener.d来调用接收方定义的方法

其实原理就是重置opener对象

发起方页面代码如下:

<body>
<iframe id="ifr" src="http://www.b.com/test/OpenerTest2.htm" style="display:none"></iframe>
</body>
<script language="javascript"  type="text/javascript">  
        var ifr = document.getElementById('ifr');
        ifr.contentWindow.opener = { a: function(msg) { alert('我调用了a方法获得了消息:' + msg); } }       
</script>

接收方页面代码如下:

<body>
</body>
<script language="javascript"  type="text/javascript">
    window.opener.a('aaa');
</script>

7、window.navigator(适用于IE6、7,貌似现在还能用,还没被补丁掉)

a、发起方页面创建一个隐藏的iframe,并且源指向接收方页面

b、发起方页面通过window.navigator.a = function(params){...}; window.navigator.b = function(params){...}; 来定义被接收方调用的方法

c、接收方页面通过window.navigator.a(params); window.navigator.b(params);来调用发起方定义的方法

d、接收方页面通过window.navigator.c = function(params){...}; window.navigator.d = function(params){...}; 来定义被发起方调用的方法

e、发起方页面通过window.navigator.c(params); window.navigator.d(params);来调用接收方定义的方法

发起方页面代码如下:

<body>
<iframe id="ifr" src="http://www.b.com/test/NavigatorTest2.htm" style="display:none"></iframe>
</body>
<script language="javascript"  type="text/javascript">
    window.navigator.a = function(msg) { alert('我调用了a方法获得了消息:' + msg); }
    window.navigator.b = function(msg) { alert('我调用了b方法获得了消息:' + msg); }
    setInterval(function() { window.navigator.c('ccc'); }, 2000);
    setInterval(function() { window.navigator.d('ddd'); }, 2000);
</script>

接收方页面代码如下:

<body>
</body>
<script language="javascript"  type="text/javascript">
    window.navigator.c = function(msg) { alert('我调用了c方法获得了消息:' + msg); }
    window.navigator.d = function(msg) { alert('我调用了d方法获得了消息:' + msg); }
    setInterval(function() { window.navigator.a('aaa'); }, 2000);
    setInterval(function() { window.navigator.b('bbb'); }, 2000);
</script>

作者:Cat Qi 出处:http://qixuejia.cnblogs.com/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

[转]JS跨域总结的更多相关文章

  1. 5种处理js跨域问题方法汇总(转载)

    1.JSONP跨域GET请求 ajax请求,dataType为jsonp.这种形式需要请求在服务端调整为返回callback([json-object])的形式.如果服务端返回的是普通json对象.那 ...

  2. JS跨域(ajax跨域、iframe跨域)解决方法及原理详解(jsonp)

    这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被 ...

  3. 前端Js跨域方法汇总—剪不断,理还乱,是跨域

    1.通过jsonp跨域2.通过修改document.domain来跨子域(iframe)3.隐藏的iframe+window.name跨域4.iframe+跨文档消息传递(XDM)5.跨域资源共享 C ...

  4. 【js跨域】js实现跨域访问的几种方式

    这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被 ...

  5. 【前端】【转】JS跨域问题总结

    详情见原博客:详解js跨域问题 概念:只要协议.域名.端口有任何一个不同,都被当作是不同的域. 跨域资源共享(CORS) CORS(Cross-Origin Resource Sharing)跨域资源 ...

  6. js跨域访问,No 'Access-Control-Allow-Origin' header is present on the requested resource

    js跨域访问提示错误:XMLHttpRequest cannot load http://...... No 'Access-Control-Allow-Origin' header is prese ...

  7. 利用JS跨域做一个简单的页面访问统计系统

    其实在大部分互联网web产品中,我们通常会用百度统计或者谷歌统计分析系统,通过在程序中引入特定的JS脚本,然后便可以在这些统计系统中看到自己网站页面具体的访问情况.但是有些时候,由于一些特殊情况,我们 ...

  8. 三种方法实现js跨域访问

    转自:http://narutolby.iteye.com/blog/1464436 javascript跨域访问是web开发者经常遇到的问题,什么是跨域,一个域上加载的脚本获取或操作另一个域上的文档 ...

  9. js跨域问题的解决

    js提交请求给别的应用实例或者别的服务器,由于同源策略,存在js跨域的情况,我所知道两种处理方式: 1.jquery ajax+jsonp <script type="text/jav ...

  10. JS 跨域问题浅析及解决方法优缺点对比(转)

    1.所谓 JS 跨域问题,是指在一个域下的页面中通过js访问另一个不同域下 的数据对象, 出于安全性考 虑,几乎所有浏览器都不允许这种跨域访问,这就导致在一些ajax应用中, 使用跨域的web ser ...

随机推荐

  1. 《Head First Servlets & JSP》-2-概述

    什么是容器 Servlet没有main()方法,他们受控于另一个Java应用,这个java应用称为容器(Container). Web服务器应用(如Apache)得到一个指向Servlet的请求(如何 ...

  2. Java 接口实际应用代码

    package interfaceDemo; interface Equipment_specifications{ void DoWork(); } class MBorad{//主板 privat ...

  3. win10开机时不显示锁屏壁纸

    win10开机壁纸存放在此目录下: C:\Users\%username%\AppData\Local\Packages\Microsoft.Windows.ContentDeliveryManage ...

  4. 用C#截取指定长度的中英文混合字符串

    很早以前写过一篇文章(用C#截取指定长度的中英文混合字符串),但是对性能没有测试,有人说我写的这个方法性能有问题,后来想,可能真会有BT之需求要求传入一个几万K甚至几M体积的字符串进来,那将会影响正则 ...

  5. ROS nodelet 理解记录

    发现网上许多的例子都是基于官网的例子,还需要做进一步的说明. 1. NODELET_DEBUG 是无法打印的信息的,需要使用NODELET_INFO NODELET_DEBUG("Addin ...

  6. Mac下的UI自动化测试 (一)

    在我看来,实现UI自动化测试的过程一向都是令人快乐的事情,而维护它们就是跟噩梦一样了,尤其是对每次CI产生的build进行BVT测试,由于开发不会告诉你任何UI的变化,那么你拿到的测试结果就势必会一片 ...

  7. 动态绑数据(GridView控件Header和ItemTemplate)

    想了解此篇文章,建议先预习一下<动态变更GridView控件列名>http://www.cnblogs.com/insus/p/3232057.html,因为多少有些关联.不管怎样,它能够 ...

  8. DropDownList 控件的SelectedIndexChanged事件触发不了

    先看看网友的问题: 根据Asp.NET的机制,在html markup有写DropDownList控件与动态加载的控件有点不一样.如果把DropDownList控件写在html markup,即.as ...

  9. metasploit 读书笔记-信息收集

    三、信息收集 被动信息收集 在不接触目标系统时进行的信息收集,包括使用工具Yeti、Whois (1)Whois msf > whois secmaniac.net (2)Netcraft:fi ...

  10. Linq to Objects for Java

    好几年不写博客了,人也慢慢变懒了.然而想写了却不知道写点啥,正好最近手头有点小项目就分享一下经历. 现在 java 的大环境下,基本都是围着 spring 转,加上一堆其他的库.有了架子就开始搞业务了 ...