下表显示了相对http://store.company.com/dir/page.html :(9500 . 163.com)的同源检测结果。
为了解决跨域的问题,我们可以使用以下方法:1 .js中的跨域通过jsonp,当我们直接使用XMLHttpRequest请求不同域的数据时,是不允许的。但是可以将不同领域的js脚本文件引入页面,jsonp就是通过这个特性实现的。例如,有一个a.html页面,其中的代码需要使用ajax来获取不同领域的json数据。假设json数据地址是http://example.com/data.php,a.html的代码可以是这样的:。
我们看到在获得的数据的地址后面有一个回调参数。习惯上使用这个参数名,但是使用其他参数也是一样的。当然,如果用于获取数据的jsonp地址页超出了您的控制范围,那么您必须按照数据提供者指定的格式进行操作。因为是作为js文件引入的,所以http://example.com/data.php必须返回一个可执行的js文件,所以这个页面的php代码可能是: 。
该页面的最终输出是: 。
所以通过http://example.com/data.php?回调=dosomething得到的js文件就是我们之前定义的dosomething函数,它的参数就是我们需要的json数据,这样我们就可以跨域得到我们需要的数据。这样就明确了jsonp的原理,通过脚本标签引入了一个js文件。js文件成功加载后,它将执行url参数中指定的函数,并传入我们需要的json数据作为参数。因此,jsonp需要服务器端页面的相应配合。了解了jsonp的跨域原理,我们就可以使用js动态生成跨域操作的脚本标签,而不是刻意手动编写那些脚本标签。如果您的页面使用jquery,您可以通过它封装的方法轻松地执行jsonp操作。
原理是一样的,只是我们不需要手动插入脚本标签和定义回退函数。Jquery会自动生成一个全局函数来替换callback=?问号中,获取数据后会自动销毁,实际上充当了临时代理功能。美元。getJSON方法会自动判断是否跨域,如果不跨域,就会调用普通的ajax方法。跨域,jsONP的回调函数将以异步加载JS文件的形式调用。2.跨域浏览器通过修改document.domain有一个对应的策略,它的一个局限性是我们不能在第一种方法中通过ajax请求来自不同来源的文档。js的第二个限制是JS不能在浏览器中不同域的框架之间进行互操作。需要注意的是,不同的框架(父子或同行)可以得到对方的窗口对象,但痛苦的是你无法使用得到的窗口对象的属性和方法(html5中的postMessage方法是个例外,ie6等一些浏览器也可以使用top和parent等少数属性)。总之,你只能得到一个几乎无用的窗口对象。比如有一个页面,它的地址是http://www.example.com/a.html,这个页面里面有一个iframe,它的src是http://example.com/b.html,很明显,这个页面和里面的iframe框架是不一样的,所以我们不能通过在页面里面写js代码来得到iframe里面的东西:。
此时,可以使用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 :
Document.domain也设置在页面http://example.com/b.html,中,这也是必需的。虽然本文档的域是example.com,但是必须显示设置document.domain的值:。
这样,我们可以通过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请求,然后我们就可以得到接收到的数据。3.使用window.name的跨域window对象具有name属性,该属性具有以下特征:在一个窗口的生命周期中,该窗口加载的所有页面共享一个window.name,并且每个页面对window.name. window.name具有读写访问权限,该属性在一个窗口加载的所有页面中保持不变,不会因加载新页面而重置。例如,有一个页面a.html,其中包含这样的代码:。
再看看b.html页面的代码:。
after页面加载三秒后,跳转到b.html页面,结果是:。
我们可以看到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中的代码:。
那么我们如何将data.html页面加载到a.html页面呢?显然,我们不能通过更改a.html页面中的window.location来直接加载data.html页面,因为即使a.html页面没有跳转,我们也希望获得data.html的数据。答案是在a.html页面使用一个隐藏的iframe作为中间人,iframe会得到data.html的数据,然后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页面的代码:。
以上代码只是最简单的原理演示代码。可以用js封装上述过程,比如动态创建iframe,动态注册各种事件等。当然,为了安全,在获取数据后,也可以销毁iframe作为代理。网上有很多类似的现成代码,有兴趣的可以去找找。通过窗口跨域,名字是这样的。使用html5中新引入的window.postMessage方法跨域传输数据。window.postmessage (message,target origin)方法是HTML5中新引入的一个特性,它可以用来向其他窗口对象发送消息,而不管这些窗口对象属于同一个源还是不同的源。目前IE8、FireFox、Chrome、Opera等浏览器已经支持window.postMessage方法。调用postMessage方法的窗口对象是指接收消息的窗口对象。此方法的第一个参数消息是要发送的消息,其类型只能是string。第二个参数targetOrigin用于定义接收消息的窗口对象的域。如果不想定义域,可以使用通配符*。需要接收消息的窗口对象可以通过监控自己的消息事件来获取发送的消息,消息内容存储在事件对象的数据属性中。向上面提到的其他窗口对象发送消息实际上是指一个页面有几个框架的情况,因为每个框架都有一个窗口对象。讨论第二种方法的时候,我们说不同域的框架可以得到对方的窗口对象,也可以使用window.postMessage的方法,看一个简单的两页的例子。
我们运行页面A后得到的结果是: 。
我们看到B页成功收到了消息。使用postMessage跨域传输数据直观方便,但缺点是IE6和IE7不支持,所以是否使用要看实际需求。