Cross-origin Communication: postMessage

项目中需要实现一个通过iframe嵌入到其它网站中的辅助工具,由于两个域间需要大量的数据交互操作,因此最近研究了一下比较可行的跨域通信方案,其中postMessage目测是最好的一个。虽然只有现代的浏览器才支持这个方法,但考虑到在其他需求中我使用addEventListener的Capture模式已经把IE6什么的给排除掉了,因此兼容性反倒不成问题。随手给个例子:

Page A postMessageA.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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>

<body>
<p></p>
<div style="border: 1px solid whiteSmoke">
<iframe src="./postMessageB.html" frameborder="0" style="width: 100%;"></iframe>
</div>
</body>

<script>
;(function () {

var theSong = '白山兮高高,黑水兮滔滔,有此山川之伟大,故生民质朴而雄豪,地所产者丰且美,俗所习者勤与劳,愿以此为基础,应世界进化之洪潮,沐三民主义之圣化,仰青天白日之昭昭,痛国难之未已,恒怒火之中烧,东夷兮狡诈,北虏兮矫骁,灼灼兮其目,霍霍兮其刀,苟捍卫之不力,宁宰割之能逃,惟卧薪而尝胆,庶雪耻于一朝,唯知行合一方为责,无取乎空论之滔滔,唯积学养气可致用,无取乎狂热之呼号,其自迩以行远,其自卑以登高,爱校、爱乡、爱国、爱人类,期终达于世界大同之目标,使命如此其重大,能不奋勉乎吾曹,能不奋勉乎吾曹!'
var lyrics = theSong.split(',')

var iframe = document.getElementsByTagName('iframe')[0]

var sing = function ( song ) {
document.getElementsByTagName('p')[0].innerHTML = song || '...'
}

var chorus = function () {
if (lyrics.length) {
sing(lyrics.shift())
iframe.contentWindow.postMessage(lyrics.shift(), '*')
}
}

var receiver = function ( event ) {
setTimeout(function () {
chorus()
}, 2000)
}
window.addEventListener('message', receiver, false)

window.onload = chorus
})()
</script>

</html>
Page B postMessageB.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
29
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<script>
;(function () {
var sing = function ( song ) {
document.getElementsByTagName('p')[0].innerHTML = song || '...'
}

var receiver = function ( event ) {
setTimeout(function () {
var lyric = event.data
if (lyric) {
sing(event.data)
event.source.postMessage('...', '*')
}
}, 2000)
}

window.addEventListener('message', receiver, false)
})()
</script>


<body>
<p>&nbsp;</p>
</body>
</html>

DEMO比较简单,就是两个页面轮流地唱校歌(准确地说是A教B唱歌),浏览器打开一下就能看到效果。值得注意的是postMessage方法中可以指定目标域,接受事件中也可以通过event.origin检查发送域,这无疑极大地提高了跨域通信的安全性,具体的介绍可以看MDN的相关文章(传送门)。