js跨域,是在不同的域之间进行数据传输或通信,比如ajax向不同域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.
只要协议,域名,端口有任何一个不同,都是不同的域
一、先进行同源检测
浏览器都有一个同源策略,其限制之一就是第一种方法中我们说的不能通过ajax的方法去请求不同源中的文档。 它的第二个限制是浏览器中不同域的框架之间是不能进行js的交互操作的。
同源策略是出于安全考虑,只允许访问本域下的接口,不同源的客户脚本在没有授权的情况下在没有授权的情况下不能读写对方的资源。
可设想一下:如果我自己建了一个网站,然后在没有支付宝客户端脚本授权的情况下轻松操控支付宝的脚本,随意传入我的个人信息,或者获得其他用户支付宝的数据,那将是非常危险的。同源策略有效地阻止了诸如此类的危险行为。
例如: 我自己建设了一个网站,这时候需要在网站上建设一个天气控件,背后的数据我必须从一些天气网站或者数据接口中进行获取,但是由于同源策略的限制,我无法实现这一目标。因此跨域就应运而生了。JS在不同域之间进行数据传输或者通信,譬如AJAX向一个不同源的服务端去请求数据,或者利用JS获取页面中不同域的iframe数据,从而实现不同域数据的相互访问,这些情境归根结底都是跨域。
链接:http://www.jianshu.com/p/1b1842fdfd73
解决跨域问题,可以通过这四种方式
一,通过jsonp跨域
在js中直接用XMLHttpRequest请求不同域上的数据时,是不可以的.
但是可以在页面上引用不同域上的js文件,却是可以的。
比如,a.html页面,他里面的代码需要利用ajax获取一个不同域上的json数据,
假设这个json数据地址是http://example.com/data.php 那么a.html中的代码为:
<script>
function dosomething(jsondata){
//处理获取的json数据
}
</script>
<script src = "http://example.com/data.php?callback=dosomething"></script>
这里的callback参数,按惯例是用这个参数名,但是你用其他的也一样。当然如果获取数据的jsonp地址页面不是你自己能控制的,就得按照提供数据的那一方的规定格式来操作了。
因为是当做一个js文件来引入的,所以http://example.com/data.php返回的必须是一个能执行的js文件,所以这个页面的php代码可能是这样的:
<?php
$callback = $_GET("callback");//得到回调函数
$data = array("a","b","c");//要返回的数据
echo $callback.'('.json_encode($data).')';//输出
?>
最后页面输出的结果是:
dosomething(['a','b','c'])
所以通过http://example.com/data.php?callback=dosomething得到的js文件,就是我们之前定义的dosomething函数,并且它的参数就是我们需要的json数据,这样我们就跨域获得了我们需要的数据。
所以jsonp的原理就是:
通过script标签引入一个js文件,这个js文件载入成功后会执行url中指定的函数,并且会把我们需要的json数据作为参数传入,因此jsonp需要服务端的页面相应的配合的.
知道jsonp跨域的原理后我们就可以用js动态生成script标签来进行跨域操作了,而不用特意的手动的书写那些script标签。如果你的页面使用jquery,那么通过它封装的方法就能很方便的来进行jsonp操作了。
<script>
$.getJSON("http://example.com/data.php?callback=?", function(jsondata){
//处理获得的json数据
})
</script>
原理是一样的,只不过我们不需要手动的插入script标签以及定义回掉函数。jquery会自动生成一个全局函数来替换callback=?中的问号,之后获取到数据后又会自动销毁,实际上就是起一个临时代理函数的作用。$.getJSON方法会自动判断是否跨域,不跨域的话,就调用普通的ajax方法;跨域的话,则会以异步加载js文件的形式来调用jsonp的回调函数。
二,通过修改document.domain来跨子域
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:
<iframe src = "http://example.com/b.html" id ="iframe" onload="test()"></iframe>
<script>
document.domain = "example.com";//设置成主域
function test(){
alert(document.getElementById("iframe").contentWindow);
}
</script>
在页面 http://example.com/b.html 中也设置document.domain,而且这也是必须的,虽然这个文档的domain就是example.com,但是还是必须显示的设置document.domain的值:
<script>
document.domain = 'example.com';//在iframe载入的这个页面也设置document.domain,使之与主页的document.domain相同
</script>
这样我们就可以通过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 属性,name属性有个特征,就是在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。
四,使用HTML5中新引进的window.postMessage方法来跨域传送数据
window.postMessage(message,targetOrigin) 方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源.