文章目录
  1. 1. 同源策略是把双刃剑
    1. 1.1. document.domain + iframe
  2. 2. 动态创建 script
  3. 3. 利用 iframe 和 location.hash
  4. 4. window.name 实现跨域数据传输
  5. 5. 使用 HTML5 的 postMessage
  6. 6. 利用flash
  7. 7. 参考来源

本文来自 网络,觉得作者写得既简短又系统,故在此做个笔记框架。

同源策略是把双刃剑

同源策略在保证了安全性(不允许跨域调用其他页面的对象)的同时,也给注入 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

1
2
3
4
5
6
7
8
9
10
11
12
13
//设置 domain 属性
document.domain = 'a.com';
//创建一个 iframe,去控制 iframe 的 contentWindow,这样两个js文件就可以相互“交互”了
var ifr = document.createElement('iframe');
ifr.src = 'http://script.a.com/page2.html';
ifr.style.display = 'none';
document.body.appendChild(ifr);
ifr.onload = function(){
var doc = ifr.contentDocument || ifr.documentWindow.document;
//可以操作 page2.html 中的元素了
}

在 script.a.com 上的 page2.html

1
2
//设置 domain 属性
document.domain = 'a.com'

关于主域名:
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//在页面中创建一个 iframe,src 指向另个域
function startRequest(){
var ifr = document.createElement('iframe');
ifr.style.display = 'none';
ifr.src = 'http://www.b.com/page2.html#paramdo';
document.body.appendChild(ifr);
}
//每隔2s去hash上检查并获取数据
function checkHash(){
try{
var data = location.hash?location.hash.substring(1):'';
console.log('数据是:', data);
}catch(e){}
}
setInterval( checkHash, 2000);

b.com 下的文件 page2.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//模拟一个简单的参数处理操作
var hash = location.hash;
switch(hash){
case '#paramdo':
// page2 在响应 page1 中 iframe 的 src 请求时
// 可以修改父的hash,进而达到 page2->page1 传递数据的目的
callBack();
break;
case '#paramdata':
// page1->page2 传递的话,直接取父的hash即可
var hash = parent.location.hash;
break;
}
//模拟子page2向父page1传递参数
function callBack(){
try{
// 把参数回传给父(另一个域)
parent.location.hash = 'somedata';
}catch(e){
// 由于不同域,ie|chrome 不允许修改 parent.location.hash(firefox 可以改)
// 所以要借助 a.com 域名下的一个代理iframe
var ifrproxy = document.createElement('iframe');
ifrproxy.style.display = 'none';
ifrproxy.src = 'http://a.com/page3.html#somedata'; //嘿!src指向另一个域
document.body.appendChild(ifrproxy);
}
}

在 a.com 域名下的代理页面 page3.html

1
2
// 因为 parent.parent 和 自身属于同一个域,所以可以改变其 locaiton.hash 值
parent.parent.location.hash = self.location.hash.substring(1);

问题:
1、数据直接暴露在了 url 中
2、数据容量和类型都有限

window.name 实现跨域数据传输

详见 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/

参考来源

JavaScript跨域总结与解决办法

文章目录
  1. 1. 同源策略是把双刃剑
    1. 1.1. document.domain + iframe
  2. 2. 动态创建 script
  3. 3. 利用 iframe 和 location.hash
  4. 4. window.name 实现跨域数据传输
  5. 5. 使用 HTML5 的 postMessage
  6. 6. 利用flash
  7. 7. 参考来源