一、什么是跨域?
跨域请求,简单说就是从一个域访问另一个域下的数据或资源。受同源策略限制,JavaScript不能跨域! 这里提到了同源策略,那么什么是同源策略呢?
同源策略(Same Origin Policy),它是由Netscape提出的一个著名的安全策略。 现在所有支持JavaScript 的浏览器都会使用这个策略。同源策略阻止从一个域上加载的脚本去获取或操作另一个域上的文档属性。也就是说,受到请求的 URL 的域必须与当前 Web 页面的域相同。这说明浏览器隔离来自不同源的内容,以防止它们之间的操作。
为何要使用同源策略?
答案:安全! 一个简单的例子:比如一个黑客,他利用Iframe把真正的银行登录页面嵌到他的页面上,当你使用真实的用户名,密码登录时,他的页面就可以通过Javascript读取到你的表单中input中的内容,这样用户名,密码就轻松到手了。后果会非常严重!
那么什么才是同源?
所谓同源是指域名,协议,端口均相同。下面罗列几种常见的情况:
URL | 说明 | 是否允许通信 |
---|---|---|
http://www.a.com/a.js http://www.a.com/b.js | 同一域名下 | 允许 |
http://www.a.com/lab/a.js http://www.a.com/script/b.js | 同一域名下不同文件夹 | 允许 |
http://www.a.com:8000/a.js http://www.a.com/b.js | 同一域名,不同端口 | 不允许 |
http://www.a.com/a.js https://www.a.com/b.js | 同一域名,不同协议 | 不允许 |
http://www.a.com/a.js http://70.32.92.74/b.js | 域名和域名对应ip | 不允许 |
http://www.a.com/a.js http://script.a.com/b.js | 主域相同,子域不同 | 不允许 |
http://www.a.com/a.js http://a.com/b.js | 同一域名,不同二级域名(同上) | 不允许(cookie这种情况下也不允许访问) |
http://www.cnblogs.com/a.js http://www.a.com/b.js | 不同域名 | 不允许 |
二、为什么要跨域?
我们实际上做项目的时候,不可避免地会根据项目需求进行跨站访问,子域和主域之间数据共享等,受到同源策略的影响,要满足这些需求,就要用跨域技术来实现。
三、如何实现跨域(前端)?
(一)document.domain
对于主域相同而子域不同的例子,可以通过设置document.domain的办法来解决。
具体做法是在主html页面(www.a.com/home.html)和iframe中被引用的html页面(auth.a.com/login.html)两个文件中分别加上document.domain = "a.com";这样在主Html下就可以访问和控制被引用的html页面中的元素了。
(二)动态创建引入JavaScript
虽然浏览器默认禁止了跨域访问,但并不禁止在页面中引用其他域的JS文件,并可以自由执行引入的JS文件中的function(包括操作cookie、Dom等等)。根据这一点,可以方便地通过创建script节点的方法来实现完全跨域的通信。
(三)使用location.hash来传值
1、主html页面(a.com/home.html)向被引用的html页面(b.com/login.html)中传值时:在路径的后面使用#hash:b.com/login.html#tyler)
2、被引用的html页面(b.com/login.html)向主html页面(a.com/home.html)传值时:
1)若是非IE、Chrome,可以直接修改parent的hash:parent.location.hash="yes";
2)若是IE、Chrome,无法修改parent的hash,要在被引用的html页面中新建iframe引入一个html页面(a.com/hash.html),通过hash传入:a.com/hash.html#yes,然后在该页面中修改主html页面的hash(由于home.html和hash.html源相同,故可以传递数据):parent.parent.hash="yes";
(四)window.name
有三个页面:
- a.com/app.html:应用页面。
- a.com/proxy.html:代理文件,一般是一个没有任何内容的html文件,需要和应用页面在同一域下。
- b.com/data.html:应用页面需要获取数据的页面,可称为数据页面。
实现起来基本步骤如下:
1. 在应用页面(a.com/app.html)中创建一个iframe,把其src指向数据页面(b.com/data.html)。
数据页面会把数据附加到这个iframe的window.name上,data.html代码如下:
<script type="text/javascript">
window.name = 'I was there!';
// 这里是要传输的数据,大小一般为2M,IE和firefox下可以大至32M左右
// 数据格式可以自定义,如json、字符串
</script>
2. 在应用页面(a.com/app.html)中监听iframe的onload事件,在此事件中设置这个iframe的src指向本地域的代理文件(代理文件和应用页面在同一域下,所以可以相互通信)。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!'
} 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>
3.获取数据以后销毁这个iframe,释放内存;这也保证了安全(不被其他域frame js访问)。
<script type="text/javascript">
iframe.contentWindow.document.write('');
iframe.contentWindow.close();
document.body.removeChild(iframe);
</script>
总结起来即:iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。
(五)HTML5 postMessage
(六)Flash
Thanks:
http://www.cnblogs.com/rainman/archive/2011/02/20/1959325.html
http://www.cnblogs.com/rainman/archive/2011/02/21/1960044.html