js 中的跨域解决办法
更新日期:
本文来自 网络,觉得作者写得既简短又系统,故在此做个笔记框架。
同源策略是把双刃剑
同源策略在保证了安全性(不允许跨域调用其他页面的对象)的同时,也给注入 iframe 和 ajax 的应用上带来了不少麻烦。
关于“同源”,此处做三点说明:
1、如果是协议|端口造成的跨域问题,在前端是无能为力的
2、跨域中的“域”仅仅是通过“URL的首部”来标识的,而不会去判断相同的ip地址是否对应着两个域 或 两个域是否在同一个ip上。
3、URL的首部,即:location.protocal + location.host。也可以理解为:domains + protocols + ports = 必须相同
在前端处理跨域的方法,一般的有以下6种:
1、document.domain + iframe
2、动态创建 script
3、利用 iframe 和 location.hash
4、window.name 实现的跨域数据传输
5、用 HTML5 中的 postMessage
6、利用 flash
document.domain + iframe
应用场景:主域相同,但子域不同
解决办法:设置 document.domain
具体做法:
在 www.a.com 上的 page1.html
|
|
在 script.a.com 上的 page2.html
|
|
关于主域名:
1、一个页面的 domain 默认是 window.location.hostname
2、主域名是不带 www 的域名,例如 a.com
3、主域名前带前缀的通常都是二级域名或多级域名,比如 www.a.com 其实是个二级域名
4、domain 只能设置成主域名,不可以将 domain 设置成 x.a.com
所以,这种方式适合于 {www.aaa.com, aaa.com, css.aaa.com, script.aaa.com} 中的任何页面间相互通信。
问题:
1、安全性,当一个站点(b.a.com)被攻击后,另一个站点(c.a.com)会引起安全漏洞
2、若一个页面中引入了多个 iframe,要想能操作所有 iframe,则必须都得设置成相同的 domain
动态创建 script
可以通过创建 script 节点的方法来实现完全跨域通信,具体做法可以参考:YUI的 Get Utility
如何判断 script 节点是否加载完毕呢,ie只能 readystatechange 属性,其他浏览器是用 script 的 load 事件。
jQuery 应该提供了兼容所有浏览器的写法~
利用 iframe 和 location.hash
这种方式虽然比较绕,但可以完全解决跨域情况下的脚本置换问题。
原理:利用 locaiton.hash 去传值。改变 hash 并不会导致页面刷新,所以可以利用 hash 来进行数据传递。在 url “http://a.com#helloword“ 中的 “#helloword” 就是 location.hash。
比如,以下两个页面想要传递消息:a.com/page1.html 和 b.com/page2.html 相互传递数据
a.com 下的文件 page1.html
|
|
b.com 下的文件 page2.html
|
|
在 a.com 域名下的代理页面 page3.html
|
|
问题:
1、数据直接暴露在了 url 中
2、数据容量和类型都有限
window.name 实现跨域数据传输
使用 HTML5 的 postMessage
HTML5 提供了跨文档消息传输 Cross Document Messaging,postMessage 支持基于 web 的实时消息传递。可参考:
《精通HTML5编程》第五章——跨文档消息机制
Window.postMessage
我之前的博客 HTML5 中的 postMessage 和 onmessage
利用flash
YUI3 中的 IO 组件中有用到:http://yuilibrary.com/yui/docs/io/