您的当前位置:首页正文

javascript跨域方法、原理以及出现问题解决方法(详解)

来源:九壹网
javascript跨域⽅法、原理以及出现问题解决⽅法(详解)

javascript跨域访问是web开发者经常遇到的问题,什么是跨域,⼀个域上加载的脚本获取或操作另⼀个域上的⽂档属性,下⾯将列出三种实现javascript跨域⽅法: 1.基于iframe实现跨域

基于iframe实现的跨域要求两个域具有aa.xx.com,bb.xx.com这种特点,也就是两个页⾯必须属于⼀个基础域(例如都是xxx.com,或是xxx.com.cn),使⽤同⼀协议(例如都是 http)和同⼀端⼝(例如都是80),这样在两个页⾯中同时添加document.domain,就可以实现⽗页⾯调⽤⼦页⾯的函数,代码如下: 页⾯⼀: Html代码

页⾯⼆:Html代码

这时候⽗页⾯就可以调⽤⼦页⾯的a函数,实现js跨域访问2.基于script标签实现跨域

script标签本⾝就可以访问其它域的资源,不受浏览器同源策略的限制,可以通过在页⾯动态创建script标签,代码如下:Java代码

var script = document.createElement('script'); script.src = \"http://aa.xx.com/js/*.js\"; document.body.appendChild(script);

这样通过动态创建script标签就可以加载其它域的js⽂件,然后通过本页⾯就可以调⽤加载后js⽂件的函数,这样做的缺陷就是不能加载其它域的⽂档,只能是js⽂件,jsonp便是通过这种⽅式实现的,jsonp通过向其它域传⼊⼀个callback参数,通过其他域的后台将callback参数值和json串包装成javascript函数返回,因为是通过script标签发出的请求,浏览器会将返回来的字符串按照javascript进⾏解析执⾏,实现了域与域之间的数据传输。 jquery中对jsonp的⽀持也是基于此⽅案。3.后台代理⽅式

这种⽅式可以解决所有跨域问题,也就是将后台作为代理,每次对其它域的请求转交给本域的后台,本域的后台通过模拟http请求去访问其它域,再将返回的结果返回给前台,这样做的好处是,⽆论访问的是⽂档,还是js⽂件都可以实现跨域。

要解决跨域的问题,我们可以使⽤以下⼏种⽅法:

⼀、通过jsonp跨域

在js中,我们直接⽤XMLHttpRequest请求不同域上的数据时,是不可以的。但是,在页⾯上引⼊不同域上的js脚本⽂件却是可以的,jsonp正是利⽤这个特性来实现的。

我们看到获取数据的地址后⾯还有⼀个callback参数,按惯例是⽤这个参数名,但是你⽤其他的也⼀样。当然如果获取数据的jsonp地址页⾯不是你⾃⼰能控制的,就得按照提供数据的那⼀⽅的规定格式来操作了。

最终那个页⾯输出的结果是:

这样jsonp的原理就很清楚了,通过script标签引⼊⼀个js⽂件,这个js⽂件载⼊成功后会执⾏我们在url参数中指定的函数,并且会把我们需要的json数据作为参数传⼊。所以jsonp是需要服务器端的页⾯进⾏相应的配合的。

知道jsonp跨域的原理后我们就可以⽤js动态⽣成script标签来进⾏跨域操作了,⽽不⽤特意的⼿动的书写那些script标签。如果你的页⾯使⽤jquery,那么通过它封装的⽅法就能很⽅便的来进⾏jsonp操作了。

原理是⼀样的,只不过我们不需要⼿动的插⼊script标签以及定义回掉函数。jquery会⾃动⽣成⼀个全局函数来替换callback=?中的问号,之后获取到数据后⼜会⾃动销毁,实际上就是起⼀个临时代理函数的作⽤。$.getJSON⽅法会⾃动判断是否跨域,不跨域的话,就调⽤普通的ajax⽅法;跨域的话,则会以异步加载js⽂件的形式来调⽤jsonp的回调函数。⼆、通过修改document.domain来跨⼦域

这样我们就可以通过js访问到iframe中的各种属性和对象了。三、使⽤window.name来进⾏跨域

window对象有个name属性,该属性有个特征:即在⼀个窗⼝(window)的⽣命周期内,窗⼝载⼊的所有的页⾯都是共享⼀个

window.name的,每个页⾯对window.name都有读写的权限,window.name是持久存在⼀个窗⼝载⼊过的所有页⾯中的,并不会因新页⾯的载⼊⽽进⾏重置。

⽐如:有⼀个页⾯a.html,它⾥⾯有这样的代码:

再看看b.html页⾯的代码:

a.html页⾯载⼊后3秒,跳转到了b.html页⾯,结果为:

我们看到在b.html页⾯上成功获取到了它的上⼀个页⾯a.html给window.name设置的值。如果在之后所有载⼊的页⾯都没对

window.name进⾏修改的话,那么所有这些页⾯获取到的window.name的值都是a.html页⾯设置的那个值。当然,如果有需要,其中的任何⼀个页⾯都可以对window.name的值进⾏修改。注意,window.name的值只能是字符串的形式,这个字符串的⼤⼩最⼤能允许2M左右甚⾄更⼤的⼀个容量,具体取决于不同的浏览器,但⼀般是够⽤了。

上⾯的例⼦中,我们⽤到的页⾯a.html和b.html是处于同⼀个域的,但是即使a.html与b.html处于不同的域中,上述结论同样是适⽤的,这也正是利⽤window.name进⾏跨域的原理。

下⾯就来看⼀看具体是怎么样通过window.name来跨域获取数据的。还是举例说明。

⽐如有⼀个www.example.com/a.html页⾯,需要通过a.html页⾯⾥的js来获取另⼀个位于不同域上的页⾯www.cnblogs.com/data.html⾥的数据。

data.html页⾯⾥的代码很简单,就是给当前的window.name设置⼀个a.html页⾯想要得到的数据值。data.html⾥的代码:

那么在a.html页⾯中,我们怎么把data.html页⾯载⼊进来呢?显然我们不能直接在a.html页⾯中通过改变window.location来载⼊

data.html页⾯,因为我们想要即使a.html页⾯不跳转也能得到data.html⾥的数据。答案就是在a.html页⾯中使⽤⼀个隐藏的iframe来充当⼀个中间⼈⾓⾊,由iframe去获取data.html的数据,然后a.html再去得到iframe获取到的数据。

充当中间⼈的iframe想要获取到data.html的通过window.name设置的数据,只需要把这个iframe的src设

为www.cnblogs.com/data.html就⾏了。然后a.html想要得到iframe所获取到的数据,也就是想要得到iframe的window.name的值,还必须把这个iframe的src设成跟a.html页⾯同⼀个域才⾏,不然根据前⾯讲的同源策略,a.html是不能访问到iframe⾥的window.name属性的。这就是整个跨域过程。看下a.html页⾯的代码:

上⾯的代码只是最简单的原理演⽰代码,你可以对使⽤js封装上⾯的过程,⽐如动态的创建iframe,动态的注册各种事件等等,当然为了安全,获取完数据后,还可以销毁作为代理的iframe。⽹上也有很多类似的现成代码,有兴趣的可以去找⼀下。通过window.name来进⾏跨域,就是这样⼦的。

四、使⽤HTML5中新引进的window.postMessage⽅法来跨域传送数据

window.postMessage(message,targetOrigin) ⽅法是html5新引进的特性,可以使⽤它来向其它的window对象发送消息,⽆论这个window对象是属于同源或不同源,⽬前IE8+、FireFox、Chrome、Opera等浏览器都已经⽀持window.postMessage⽅法。

调⽤postMessage⽅法的window对象是指要接收消息的那⼀个window对象,该⽅法的第⼀个参数message为要发送的消息,类型只能为字符串;第⼆个参数targetOrigin⽤来限定接收消息的那个window对象所在的域,如果不想限定域,可以使⽤通配符 * 。需要接收消息的window对象,可是通过监听⾃⾝的message事件来获取传过来的消息,消息内容储存在该事件对象的data属性中。上⾯所说的向其他window对象发送消息,其实就是指⼀个页⾯有⼏个框架的那种情况,因为每⼀个框架都有⼀个window对象。在讨论第⼆种⽅法的时候,我们说过,不同域的框架间是可以获取到对⽅的window对象的,⽽且也可以使⽤window.postMessage这个⽅法。下⾯看⼀个简单的⽰例,有两个页⾯

我们运⾏a页⾯后得到的结果:

我们看到b页⾯成功的收到了消息。

使⽤postMessage来跨域传送数据还是⽐较直观和⽅便的,但是缺点是IE6、IE7不⽀持,所以⽤不⽤还得根据实际需要来决定。结语:

除了以上⼏种⽅法外,还有flash、在服务器上设置代理页⾯等跨域⽅式,这⾥就不做介绍了。

以上四种⽅法,可以根据项⽬的实际情况来进⾏选择应⽤,个⼈认为window.name的⽅法既不复杂,也能兼容到⼏乎所有浏览器,这真是极好的⼀种跨域⽅法。

以上就是本⽂介绍javascript跨域⽅法、原理以及出现问题解决⽅法的全部内容,希望对⼤家有所帮助。

因篇幅问题不能全部显示,请点此查看更多更全内容

Top