html5 postMessage解决跨域、跨窗口消息传递

Cross-document messaging

 

平时做web开发的时候关于消息传递,除了客户端与服务器传值,还有几个经常会遇到的问题

 

1..多窗口之间消息传递

 

2.主页面与嵌套的iframe消息传递

 

上面问题的跨域数据传递如何进行?

 

由于同源策略的限制,JavaScript 跨域的问题,一直是一个颇为棘手的问题。

 

HTML5 提供了在网页文档之间互相接收与发送信息的功能。使用这个功能,只要获取到网页所在窗口对象的实例,不仅同源(域 + 端口号)的 Web 网页之间可以互相通信,甚至可以实现跨域通信。  

 

要想接收从其他窗口发送来的信息,必须对窗口对象的 onmessage 事件进行监听,其它窗口可以通过 postMessage 方法来传递数据。

 

postMessage 的作用就是传递数据,而 onmessage 的作用就是接收数据

 

发送消息

 

windowObj.postMessage(data,origin)方法说明:

 

1windowObj: 窗口的一个引用,比如iframecontentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。(接收方窗口的引用)

 

2data:要传递的数据,html5规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候需要使用JSON.stringify()方法对对象参数序列化。

 

3origin:字符串参数,指明目标窗口的源,协议+主机+端口号,这个参数是为了安全考虑,postMessage()方法只会将message传递给指定窗口,当然如果愿意也可以将参数设置为"*",这样可以传递给任意窗口(好像不是这样),如果要指定和当前窗口同源的话设置为"/"

 

接收消息

 

注册事件监听

element.addEventListener(event, function, useCapture);

第一个参数是事件的类型 ( "click" "mousedown"等等).

 

第二个参数是事件触发后调用的函数。

 

第三个参数是个布尔值用于描述事件是冒泡还是捕获。该参数是可选的。

 

注意:event不要使用 "on" 前缀。 例如,使用 "click" ,而不是使用 "onclick"

 

事件冒泡或事件捕获?

事件传递有两种方式:冒泡与捕获。

 

事件传递定义了元素事件触发的顺序。 如果你将 <p> 元素插入到 <div> 元素中,用户点击 <p> 元素, 哪个元素的 "click" 事件先被触发呢?

 

冒泡 中,内部元素的事件会先被触发,然后再触发外部元素,即: <p> 元素的点击事件先触发,然后会触发 <div> 元素的点击事件。

 

捕获 中,外部元素的事件会先被触发,然后才会触发内部元素的事件,即: <div> 元素的点击事件先触发 ,然后再触发 <p> 元素的点击事件。

 

addEventListener() 方法可以指定 "useCapture" 参数来设置传递类型:

 

addEventListener(event, function, useCapture);

默认值为 false, 即冒泡传递,当值为 true , 事件使用捕获传递。

 

关于message事件

onmessage      该事件通过或者从对象(WebSocket, Web Worker, Event Source 或者子 frame 或父窗口)接收到消息时触发。

 

测试示例(跨域:父窗口 127.0.0.1 ,子窗口 localhost):

http://127.0.0.1:8080/test01/parent.html

<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
<title>Test Cross-domain communication using HTML5</title> 
<script type="text/JavaScript">
    function sendMsg(){ 
        // 通过 postMessage 向子窗口发送数据
       document.getElementById("otherPage").contentWindow
            .postMessage( 
                document.getElementById("message").value, 
               //"http://localhost:8080"
               "*"
            ); 
    } 
    
  window.addEventListener("message", function( event ) { 
    	alert(event.data);
    }, false ); 
</script>
</head> 
<body> 
    <!-- 通过 iframe 嵌入子页面 -->
    <iframe src="http://localhost:8080/test01/child.html" id="otherPage" >
    </iframe>
    <br/><br/> 
    <input type="text" id="message">
    <input type="button" value="Send to localhost" onclick="sendMsg()" /> 
</body> 
</html>

 

http://localhost:8080/test01/child.html

<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
<title>Web page from child.com</title> 
<script type="text/JavaScript">
    
    //event 参数中有 data 属性,就是父窗口发送过来的数据
    window.addEventListener("message", function( event ) { 
    	
    	//检查事件来源
    	if(event.origin !== 'http://127.0.0.1:8080'){
    		return;
    	} 
        // 把父窗口发送过来的数据显示在子窗口中
       document.getElementById("content").innerHTML+=event.data+"<br/>"; 
       
       //回复消息
       event.source.postMessage('ok!',
    		   //event.origin
    		   "*"
    		   );
    }, false ); 
 
</script>
</head> 
<body> 
    Web page from http://localhost:8080 
    <div id="content"></div> 
</body> 
</html>

 

通过浏览器访问:http://127.0.0.1:8080/test01/parent.html

输入 hello,点击发送按钮。



 

MessageEvent属性



 

 

不解的地方:

windowObj.postMessage(data,origin),既然windowObj是接收方窗口的引用,那么接收方就固定了,指定origin又有什么意义呢?

 

 

 

 

 

 

 

 

猜你喜欢

转载自huangqiqing123.iteye.com/blog/2412081
今日推荐