宝哥软件园

javascript跨域方法、原理及解题方法(详解)

编辑:宝哥软件园 来源:互联网 时间:2021-09-08

Javascript跨域访问是web开发人员遇到的常见问题。什么是跨域?加载在一个域上的脚本获取或操作另一个域上的文档属性。以下是实现javascript跨域: 1的三种方法。基于iframe实现跨域。

基于iframe的跨域实现要求两个域具有aa.xx.com、bb.xx.com的特性,即两个页面必须属于一个基本域(例如都是xxx.com或xxx.com.cn),并且使用相同的协议(例如都是http)和相同的端口(例如都是80),这样通过同时给两个页面添加document.domain,父页面就可以调用子页面的函数。

html头部脚本document . domain=' xx.com ';函数aa(){ alert(' p ');}/script/head body iframe src=' http :http://localhost :8080/CmSui/2 . html ' id=' I '/iframe script document . getelementbyid(' I ')。onload=function(){ var d=document . getelementbyid(' I ')。contentWindowd . a();};/script /body /html第2页:

Html代码

html头部脚本document . domain=' xx.com ';函数a(){ alert(' c ');} /script /head body /body /html此时,父页面可以调用子页面的A函数,实现js跨域访问

2.基于脚本标签的跨域实现

脚本标签可以自己访问其他域的资源,不受浏览器同源策略的限制。可以在页面上动态创建脚本标签,代码如下:

Java代码

var script=document . createelement(' script ');'http://aa.xx.com/js/*。js ';document.body.appendChild(脚本);这样可以通过动态创建脚本标签来加载其他域的js文件,然后通过这个页面调用加载的js文件的函数。这样做的缺陷是不能加载其他域的文档,只能加载js文件。jsonp就是这样实现的。jsonp向其他域传递一个回调参数,将回调参数值和json字符串打包成javascript函数通过其他域的后台返回,由于请求是通过脚本标签发送的,浏览器会根据javascript解析并执行返回的字符串,从而实现域间的数据传输。jquery中jsonp的支持也是基于这个方案。

3.后台代理模式

这种方法可以解决所有的跨域问题,即后台作为代理,对其他域的每一个请求都转移到这个域的后台。该域的后台通过模拟http请求访问其他域,然后将返回的结果返回给前台。这种方法的优点是,无论是访问文档还是js文件,都可以实现跨域。

下表给出了相对http://store.company.com/dir/page.html:的同源检测结果

QQ截图20130613230631

要解决跨域问题,我们可以使用以下方法:

第一,通过jsonp跨域

在js中,当我们直接使用XMLHttpRequest请求不同域的数据时,是不允许的。但是可以将不同领域的js脚本文件引入页面,jsonp就是通过这个特性实现的。

例如,有一个a.html页面,其中的代码需要使用ajax来获取不同领域的json数据。假设json数据地址是http://example.com/data.php,a.html的代码可以是这样的:

QQ截图20130613230631

我们可以看到在数据的地址后面还有一个回调参数。习惯上使用这个参数名,但使用其他参数时也是如此。当然,如果用于获取数据的jsonp地址页超出了您的控制范围,那么您必须按照数据提供者指定的格式进行操作。

因为它是作为js文件引入的,所以http://example.com/data.php必须返回一个可执行的js文件,所以这个页面的php代码可能是这样的:

QQ截图20130613230631

该页面的最终输出是:

QQ截图20130613230631

所以通过http://example.com/data.php?回调dosome得到的js文件就是我们之前定义的dosome函数,它的参数就是我们需要的json数据,这样就可以跨域得到我们需要的数据。

这样,jsonp的原理就清晰了。js文件是通过脚本标签引入的。js文件成功加载后,将执行url参数中指定的函数,我们需要的json数据将作为参数传入。因此,jsonp需要服务器端页面的相应配合。

了解了jsonp的跨域原理,我们就可以使用js动态生成跨域操作的脚本标签,而不是手动编写那些脚本标签。如果您的页面使用jquery,那么通过它封装的方法可以很容易地用于jsonp操作。

QQ截图20130613230631

原理是一样的,只是我们不需要手动插入脚本标签和定义回退函数。Jquery会自动生成一个全局函数来代替callback=?获取数据后,会自动销毁,实际上起到了临时代理功能的作用。美元。getJSON方法会自动判断是否跨域,如果没有跨域,会调用普通的ajax方法;跨域,会以异步加载JS文件的形式调用jsONP的回调函数。

第二,通过修改document.domain来跨子域

浏览器有一个相应的策略,它的一个局限性是我们不能在第一种方法中通过ajax请求来自不同来源的文档。它的第二个限制是js不能在浏览器中不同域的框架之间进行互操作。需要注意的是,不同的框架(父子或对等)可以得到对方的窗口对象,但痛苦的是你无法使用得到的窗口对象的属性和方法(html5中的postMessage方法是个例外,ie6等一些浏览器也可以使用top和parent等少数属性)。简而言之,你只能得到一个几乎无用的窗口对象。例如,有一个页面,它的地址是http://www.example.com/a.html,这个页面中有一个iframe,它的src是http://example.com/b.html,显然,这个页面和它里面的iframe框架不同,所以我们不能通过在页面中编写js代码来得到iframe中的内容:

QQ截图20130613230631

此时,可以使用document.domain。我们只需要将http://www.example.com/a.html和http://example.com/b.html的document.domain设置为同一个域名。然而,应该注意的是,document.domain的设置是有限的。我们只能将document.domain设置为自己的域或更高级别的父域,并且主域必须相同。例如,a.b.example.com文档的document.domain可以设置为a.b.example.com、b.example.com和example.com中的任何一个,但不能设置为c.a.b.example.com,因为它是当前域的子域,也不能设置为Baidu.com,因为主域不同。

在http://www.example.com/a.html页面设置document.domain:

QQ截图20130613230631

Document.domain也设置在页面http://example.com/b.html,中,这也是必需的。虽然此文档的域是example.com,但是必须显示设置document.domain的值:

QQ截图20130613230631

这样,我们可以通过js访问iframe中的各种属性和对象。

但是,如果您想直接通过http://www.example.com/a.html页面中的ajax请求http://example.com/b.html页面,即使您设置了相同的document.domain,它也不会起作用。因此,修改document.domain的方法只适用于不同子域中框架之间的交互。如果您想通过ajax与不同子域中的页面进行交互,除了jsonp之外,您还可以使用隐藏的iframe作为代理。其原理是将这个iframe加载到一个页面中,该页面与您想要通过ajax获取数据的目标页面位于同一个域中,因此这个iframe中的页面通常可以使用ajax来获取您想要的数据。然后,我们可以通过刚才提到的修改document.domain的方法,通过js完全控制这个iframe,这样我们就可以让iframe发送ajax请求,然后我们就可以得到接收到的数据了。

第三,使用window.name跨域

window对象有一个name属性,这个属性有一个特点:在一个窗口的生命周期中,该窗口加载的所有页面共享一个window.name,并且每个页面对window.name. window.name都有读写权限,在一个窗口加载的所有页面中都存在,不会因为加载新页面而重置。

例如,有一页a.html有这样的代码:

QQ截图20130613230631

看看b.html网页上的代码:

QQ截图20130613230631

after页面加载三秒钟后,它跳到b.html页面,结果是:

QQ截图20130613230631

我们可以看到,a.html在《b.html》上一页设置的window.name值被成功获取。如果以后所有加载的页面都没有修改window.name,那么所有这些页面获得的window.name的值就是a.html页面设置的值。当然,如果需要,任何页面都可以修改window.name的值。请注意,window.name的值只能是字符串形式。根据不同的浏览器,这个字符串的最大大小可以是2M左右,甚至更大,但一般来说已经足够了。

在上面的例子中,a.html和b.html的页面在同一个域中,但是即使a.html和b.html在不同的域中,上面的结论也是适用的,这就是使用window.name来跨域的原理。

让我们看一下如何通过窗口获取跨域数据。

例如,如果有一个www.example.com/a.html页面,您需要通过a.html页面中的js获取位于不同域中的另一个页面的www.cnblogs.com/data.html数据。

data.html页面中的代码非常简单,就是为当前窗口设置一个数据值。a.html页面想要获取的名称。data.html中的代码:

QQ截图20130613230631

那么我们如何将data.html页面加载到a.html页面呢?显然,我们不能通过更改a.html页面中的window.location来直接加载data.html页面,因为即使a.html页面没有跳转,我们也希望获得data.html的数据。答案是使用a.html页面中隐藏的iframe作为中间人,然后a.html将获得iframe获得的数据。

如果一个充当中间人的iframe想要获取window.name在data.html设置的数据,它只需要将这个iframe的src设置为www.cnblogs.com/data.html.那么,如果a.html想要获取iframe获取的数据,也就是获取window.name的值,他还必须将iframe的src设置为与a.html页面相同的域。否则,根据上述同源策略,a.html不能访问iframe中的window.name属性。这是整个跨域的过程。

看看a.html的代码页:

QQ截图20130613230631

以上代码只是最简单的原理演示代码。可以用js封装上述过程,比如动态创建iframe,动态注册各种事件等。当然,为了安全,在获取数据后,也可以销毁iframe作为代理。网上有很多类似的现成代码,有兴趣的可以去找找。

通过窗口跨域,名字是这样的。

第四,使用HTML5中新引入的window.postMessage方法跨域传输数据

窗户。postmessage (message,target origin)是html5新引入的功能,它可以用来向其他窗口对象发送消息,而不管这些窗口对象属于同一个源还是不同的源。目前,IE8、FireFox、Chrome和Opera等浏览器已经支持该窗口。事后分析方法。

调用postMessage方法的窗口对象是指接收消息的窗口对象。此方法的第一个参数消息是要发送的消息,其类型只能是string。第二个参数targetOrigin用于定义接收消息的窗口对象的域。如果不想定义域,可以使用通配符*。

需要接收消息的窗口对象可以通过监控自己的消息事件来获取发送的消息,消息内容存储在事件对象的数据属性中。

向上面提到的其他窗口对象发送消息实际上是指一个页面有几个框架的情况,因为每个框架都有一个窗口对象。在讨论第二种方法时,我们说过不同域中的框架可以获得彼此的窗口对象,也可以使用window.postMessage的方法,我们来看一个简单的两页示例

QQ截图20130613230631

QQ截图20130613230631

运行A页面后得到的结果是:

QQ截图20130613230631

我们看到页面B成功接收到消息。

使用postMessage跨域传输数据直观方便,但缺点是IE6和IE7不支持,所以是否使用要看实际需求。

结论:

除了以上方法,还有服务器上的flash、设置代理页面等跨域方法,这里就不介绍了。

以上四种方法可根据项目实际情况选择应用。个人认为window.name的方法既不复杂,也不兼容几乎所有的浏览器,确实是一个优秀的跨域方法。

以上就是本文要介绍的javascript跨域方法、原理以及解决问题的方法,希望对大家有所帮助。

更多资讯
游戏推荐
更多+