当前位置: 代码迷 >> Web前端 >> 跨域小结
  详细解决方案

跨域小结

热度:395   发布时间:2012-10-07 17:28:51.0
跨域总结
前端的需要掌握的知识储备要远远的大于实践

浏览器安全模型规定,XMLHttpRequest、框架(frame)等只能在一个域中通信。从安全角度考虑,这个规定很合理;但是,也确实给分布式(面向服务、混搭等等本周提到的概念)Web开发带来了麻烦。

所谓的跨域就是,a.com 域名下的js无法操作b.com或是c.a.com域名下的对象

第一种:
window.name:就是window对象上的一个属性,只要窗口不发生变化(打开的不为_blank),这个值是一直存在,不会发生改变

a.com/app.html:
a.com/proxy.html:内容空白
b.com/data.html


需求:a.com/app.html需要访问b.com/data.html里面的数据
实现:在a.com/app.htm上加入一个iframe,然后src指向b.com/data.html,在b.com/data.html会执行一段脚本,将数据写入window.name上,这个时候a.com/app.html会执行iframe的onload函数将window.name读取进来,然后将src指向空白界面a.com/proxy.html

b.com/data.html
<script type="text/javascript">
    window.name = 'I was there!';
</script>


a.com/app.html
<script type="text/javascript">
    var state = 0, 
    iframe = document.createElement('iframe'),
    loadfn = function() {
        if (state === 1) {
            var data = iframe.contentWindow.name;    // 读取数据
            alert(data);    //弹出'I was there!'
            //删除iframe
            iframe.contentWindow.document.write('');
            iframe.contentWindow.close();
            document.body.removeChild(iframe);
        } else if (state === 0) {
            state = 1;
            iframe.contentWindow.location = "http://a.com/proxy.html";
        }  
    };
    iframe.src = 'http://b.com/data.html';
    if (iframe.attachEvent) {
        iframe.attachEvent('onload', loadfn);
    } else {
        iframe.onload  = loadfn;
    }
    document.body.appendChild(iframe);
</script>


iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作

摘至:http://www.cnblogs.com/rainman/archive/2011/02/21/1960044.html

第二种:
iframe + location.hash : 利用location.hash来进行传值,http://a.com#helloword中的‘#helloworld’就是location.hash,最重要的是改变hash并不会导致页面刷新

需求:a.com下的文件cs1.html要和cnblogs.com域名下的cs2.html传递信息
实现:cs1.html首先创建自动创建一个隐藏的iframe,iframe的src指向cnblogs.com域名下的cs2.html页面,这时的hash值可以做参数传递用。cs2.html响应请求后再将通过修改cs1.html的hash值来传递数据(由于两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值,所以要借助于a.com域名下的一个代理iframe;因为parent.parent和自身属于同一个域,所以可以改变其location.hash的值
而Firefox可以修改)。同时在cs1.html上加一个定时器,隔一段时间来判断location.hash的值有没有变化,一点有变化则获取获取hash值。

a.com/cs1.html
function startRequest(){
    var ifr = document.createElement('iframe');
    ifr.style.display = 'none';
    ifr.src = 'http://www.cnblogs.com/lab/cscript/cs2.html#paramdo';
    document.body.appendChild(ifr);
}

function checkHash() {
    try {
        var data = location.hash ? location.hash.substring(1) : '';
        if (console.log) {
            console.log('Now the data is '+data);
        }
    } catch(e) {};
}
setInterval(checkHash, 2000);


cnblogs.com/cs2.html:
//模拟一个简单的参数处理操作
switch(location.hash){
    case '#paramdo':
        callBack();
        break;
    case '#paramset':
        //do something……
        break;
}

function callBack(){
    try {
        parent.location.hash = 'somedata';
    } catch (e) {
        // ie、chrome的安全机制无法修改parent.location.hash,
        // 所以要利用一个中间的cnblogs域下的代理iframe
        var ifrproxy = document.createElement('iframe');
        ifrproxy.style.display = 'none';
        ifrproxy.src = 'http://a.com/test/cscript/cs3.html#somedata';    // 注意该文件在"a.com"域下
        document.body.appendChild(ifrproxy);
    }
}


当然这样做也存在很多缺点,诸如数据直接暴露在了url中,数据容量和类型都有限等……

摘至:http://www.cnblogs.com/rainman/archive/2011/02/20/1959325.html

第三种:
window.opener:window的一个属性,它返回的是打开当前窗口的窗口对象,如果窗口A弹出一个窗口B,那么在B中window.opener就是窗口对象A
(友情提示:当你通过open打开了一个新窗口后,确保在新窗口中将opener属性设置为null(空).如果不这样的话,会使浏览器持续的保留每个opener的值,直至资源耗尽)

需求:建立1.htm,它用open方法打开2.htm,现在让2.htm给1.htm提供数据
原理:通过2.htm的opener来操控1.htm的location

1.htm
<script language="JavaScript">
window.open('2.htm', ', 'width=225,height=235,resizable=1,scrollbars=auto');
</script>


2.htm
<script language="JavaScript">
function ccc()
{
window.opener.document.bgColor='red';
}
function xxx()
{
window.opener.document.location='http://angel1949.blogcn.co...
}

<input type="submit" name="Submit" value="变色" onClick="ccc()">
<input type="submit" name="Submit1" value="转向" onClick="xxx()">


这种方法适合弹出框跨域和window.parent的iframe跨域是完全不同的

摘至:http://blog.csdn.net/mpu/article/details/1375301

第四种:
JSONP:虽然浏览器默认禁止了跨域访问,但并不禁止在页面中引用其他域的JS文件,并可以自由执行引入的JS文件中的function

需求:a.html放问b.do数据
原理:在a.html动态创建一个script标签,向不同域的b.do发送请求,b.do返回一段js脚本在客户端立即执行,里面直接向回调函数注入数据

a.html
<script>
function callback(data){
alert("haha")
}
</script>
<script src="b.do?cb=callback"></script>

b.do服务器端返回
callback({name:"cc",age:"25"})

这样callback({name:"cc",age:"25"})会当做脚本直接在客户端执行,就实现了跨域请求数据的效果

JSONP 服务返回打包在函数调用中的 JSON 响应,而函数调用是由浏览器执行的,这使宿主 Web 应用程序更容易受到各类攻击。

第五种:
flash当跨域访问资源时,例如从域www.a.com请求域www.b.com上的数据,我们可以借助Flash来发送HTTP请求,不过对方域crossdomain.xml上要有授权

原理:使用URLLoader向目标域发一段请求,得到数据之后在通过ExternalInterface调用js的方法,将数据注入进去

代码略~~

第六种:
服务器代理,虽然浏览器的同源策略限制跨域请求,但在服务器端发送http请求就没有这限制了(比如说爬虫器)

原理:比如www.a.com要访问www.b.com里的数据,可以创建一个www.a.com/proxy代理,因为www.a.com和www.a.com/proxy是在同域不受限制,首先www.a.com会request给www.a.com/proxy,www.a.com/proxy会在服务器端向www.b.com发送请求,得到数据之后在response给www.a.com(用到了点长轮询的概念)

其他跨域方式:
Access Control
原理:请求的响应必须包含一个Access-Control-Allow-Origin的HTTP响应头,如:header("Access-Control-Allow-Origin: http://www.a.com");
局限:Firefox, Google Chrome等通过XMLHTTPRequest实现,IE8下通过XDomainRequest实现

document.domain
原理:将document的domain属性都修改为xx.com
局限:只能在子域之间通信

window.postMessage
原理:HTML5定义的一个很新的方法
局限:在很旧和比较旧的浏览器中都无法使用(ie6,7,8)

摘至:http://ued.koubei.com/?p=1291

6大类基本包括了绝大的部分,其他的就是根据项目量体裁衣了,欢迎其他高手补充~
  相关解决方案