本文探讨用于构建实时(real-time)跨域(cross-origin)通信的两个重要模块:跨文档消息通讯和XMLHttpRequest Level 2。通过它们,我们可以构建引人注目的Web应用,作为HTML5应用新的通信手段,这两个构建块可以让不同域间的web应用安全地进行通信。

跨文档消息通信

处于安全方面考虑,运行在同一浏览器中的框架、标签页、窗口之间的通讯一直受到严格的限制。例如,在浏览器内部共享信息对某些站点可能比较方便,但是同时也增加了收到恶意攻击的可能性。如果浏览器允许程序访问加载到其他框架和标签的内容,某些网站就能够利用脚本窃取其他网站的某些信息。浏览器厂商合理第限制了这类访问,当尝试检测或修改从其他源加载的内容时,浏览器会抛出安全异常,并组织相应的操作。

然而,实际中存在一些合理的让不同站点的内容能在浏览器内进行交互的需求,如果浏览器内部提供直接的通信机制,就能更好地组织这些应用:跨文档消息通信。

跨文档消息通信可以确保iframe、标签页、窗口之间安全的进行跨源通信。PostMessage是Windows API(应用程序接口) 中的一个常用函数,用于将一条消息放入到消息队列中。该方法可以通过绑定window的message事件来监听发送跨文档消息传输内容。

在父网页中通过 iframe 嵌入子页面,并在 JavaScript 代码中调用 postMessage 方法发送数据到子窗口。

父页面中嵌入子页面,调用 postMessage 方法发送数据
  1. <html>
  2. <head>
  3. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  4. <title>Test Cross-domain communication using HTML5</title>
  5. <script type="text/JavaScript">
  6. function sendIt(){
  7. // 通过 postMessage 向子窗口发送数据
  8. document.getElementById("otherPage").contentWindow
  9. .postMessage(
  10. document.getElementById("message").value,
  11. "http://loverMap.sinaapp.com"
  12. );
  13. }
  14. </script>
  15. </head>
  16. <body>
  17. <!-- 通过 iframe 嵌入子页面 -->
  18. <iframe src="http://loverMap.sinaapp.com/test/child.html"
  19. id="otherPage"></iframe>
  20. <br/><br/>
  21. <input type="text" id="message"><input type="button"
  22. value="Send to child.com" onclick="sendIt()" />
  23. </body>
  24. </html>

在子窗口中监听 onmessage 事件,并用 JavaScript 实现显示父窗口发送过来的数据。

子窗口中监听 onmessage 事件,显示父窗口发送来的数据
  1. <html>
  2. <head>
  3. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  4. <title>Web page from child.com</title>
  5. <script type="text/JavaScript">
  6. //event 参数中有 data 属性,就是父窗口发送过来的数据
  7. window.addEventListener("message", function( event ) {
  8. // 把父窗口发送过来的数据显示在子窗口中
  9. document.getElementById("content").innerHTML+=event.data+"<br/>";
  10. }, false );
  11.  
  12. </script>
  13. </head>
  14. <body>
  15.  
  16. <div id="content"></div>
  17. </body>
  18. </html>

演示地址:http://lovermap.sinaapp.com/test/parent.html

在postMessage之前,iframe间的通信有时会通过直接写脚本来实现。通过执行一个页面中的脚本来尝试操纵另一个文件。这种方式,可能会因为安全限制而被进制,因而postMessage取代了直接编程访问,它提供了javascript环境中的异步通信机制。

假如没有postMessage,跨源通信导致安全错误,为防止跨站点(cross-site)脚本攻击,浏览器会强制引发这种安全限制。

  1. Error:Permission denied for <http://localhost:8080>to get property window.document from <http://loverMap.sinaapp.com>

理解源安全

源是在网络上应用建立信任关系的地址的子集。源有规则(scheme)、主机(host)、端口(port)组成。

html5 定义源的序列化,源在API和协议中以字符串的形式出现,对于使用XMLHttpRequest进行跨域HTTP请求是非常重要,对WebSocket也一样。

在处理跨源通信的消息时,一定要验证每个消息的源。此外,处理消息同的数据时也应该谨慎。即使消息来自可信源,也应该像对待外部输入时一样仔细。

element.innerHTML = e.data,是危险的因为e.data,会被当作标记;而element.textContent = e.data则是相对安全的。最好不要用第三方的字符串求值,另外,避免使用eval方法处理应用内部的字符串,可以通过window.JSON或者json.org解析器使用JSON。

浏览器支持

  1. if(typeof window.postMessage == "undefined"){
  2. //浏览器不支持postMessage
  3. }

发送消息

  1. window.postMessage( document.getElementById("message").value, "http://loverMap.sinaapp.com");

该方法使用两个参数:第一个参数为所发送的消息文本,但也可以是任何 JavaScript 对象(通过 JSON 转换对象为文本),第二个参数为接收消息的对象窗口的 URL 地址,可以在 URL 地址字符串中使用通配符'*'指定全部地。方法使用两个参数:第一个参数为所发送的消息文本,但也可以是任何 JavaScript 对象(通过 JSON 转换对象为文本),第二个参数为接收消息的对象窗口的 URL 地址,可以在 URL 地址字符串中使用通配符'*'指定全部地。

监听消息事件

脚本可以通过监听window对象中的事件来接受信息。

  1. window.addEventListener("message", function( event ) {
  2. document.getElementById("content").innerHTML+=event.data+"<br/>"; }, false );

实例的应用的运行依赖于两个先决条件:首先,页面需要部署在web服务器上;其次,两个页面必须来自不同的域。如果可以访问位于不同的域的多个web服务器,那么将实例文件部署到服务器之后,实例就能顺利运行了。

XMLHttpRequest Level 2

XMLHttpRequest API使得AJAX技术的实现成为可能。作为XMLHttpRequest的改进版,,XMLHttpRequest Level 2在功能上有很大的改进。主要集中在两方面:

1)跨域XMLHttpRequest

2)进度事件。

 传统的XMLHttpRequest 

  1. var xhr = new XMLHttpRequest();
  2. xhr.open('GET', 'example.php');
  3. xhr.send();
  4. xhr.onreadystatechange = function(){
  5.     if ( xhr.readyState == 4 && xhr.status == 200 ) {
  6.       console.info( xhr.responseText );
  7.     } else {
  8.       console.info(xhr.statusText );
  9.     }
  10.   };

包含XMLHttpRequest的主要属性

xhr.readyState:xhr对象的状态,等于4表示数据接受完毕。

xhr.status:服务器返回的状态码,等于200表示一切正常。

xhr.responseText:服务器返回的xml格式的数据。

xhr.statusText:服务器返回的状态文本。

但是传统的XMLHttpRequest具有一下缺点

1)只支持文本数据的传送,无法用来读取和上传二进制文件。

2)传送和接收数据时,没有进度信息,只能提示有没有完成。

3)受到同源限制,只能向同一域名的服务器请求数据。

跨域XMLHttpRequest

过去XMLHttpRequest仅限于同源通信。XMLHttpRequest Level 2通过CORS(跨源资源共享)实现XMLHttpRequests。由于路径可能包含敏感信息,为了保护用户隐私,浏览器不一定会发送Referer,而浏览器在任何必要的时候都会发送Origin头部。

使用跨源XMLHttpRequest可以构建基于非同源服务的web应用程序。

通过跨源XMLHttpRequest可以从客户端整合来自不同源的内容,如果目标服务器允许,可以使用用户证书访问受保护的内容,进而让让用户直接访问个人的数据。反之,如果通过服务器端不对同源进行整合,则所有内容都要穿过一个服务器端的基础层,因此可能会形成瓶颈。

其实新版的XMLHttpRequest除了请求不同域名下的数据(跨域请求),还做出以下进步:

1)可以设置HTTP请求的时限。

2)可以使用FormData对象管理表单数据。

3)可以上传文件。

4)可以获取服务器的二进制数据。

5)可以获取数据传输的进度信息。

浏览器支持情况检测

  1. var xhr = new XMLHttpRequest();
  2. if(typeof xhr.withCredentials === undefined){
  3. document.getElementById("support").innerHTML = "you brower does not support"
  4. }else{
  5. document.getElementById("support").innerHTML = "you brower support"
  6. }

构建跨域请求

XMLHttpRequest,首先要创建一个新的XMLHttpRequest对象,

接下来通过指定不同源的地址来构造跨源的XMLHttpRequest:

在请求过程中务必确保能够监听到错误,请求不成功很多原因,如网络故障、访问被拒、目标服务器缺乏对CORS支持等。

从其他源获取数据的一种常见方式是使用JSONP,使用JSONP设计创建script标签,其中包含指向JSON资源的URL。URL包含了脚本加载时将要调用的函数的名称,有远程服务器负责包装JSON数据,并调用命名函数。这种方式存在重大的安全隐患。因为在使用JSONP时,你必须完全信任服务端所提供的数据,恶意的脚本能够接管你的应用。

构建跨源请求

  1. var xhr = new XMLHttpRequest();
  2.  
  3. xhr.open("POST", targetLocation, true);

使用进度时间

  1. function() {
  2. xhr.upload.onprogress = function(e) {
  3. var ratio = e.loaded / e.total;
  4. setProgress(ratio + "% 上传中");
  5. }
  6. 设置回调函数以处理进度时间,并计算上传和下载的完成率
  7. xhr.onprogress = function(e) {
  8. var ratio = e.loaded / e.total;
  9. setProgress(ratio + "% 加载中");
  10. }
  11.  
  12. xhr.onload = function(e) {
  13. setProgress("上传完毕");
  14. }
  15.  
  16. xhr.onerror = function(e) {
  17. setProgress("错误");
  18. }
  19.  
  20. xhr.open("POST", targetLocation, true);
  21.  
  22. geoDataString = dataElement.textContent;
  23. xhr.send(geoDataString);
  24. }, true);

演示地址:http://lovermap.sinaapp.com/test/crossOriginUpload.html

HTML5 Communication API的更多相关文章

  1. HTML5 程序设计 - 使用HTML5 Canvas API

    请你跟着本篇示例代码实现每个示例,30分钟后,你会高喊:“HTML5 Canvas?!在哥面前,那都不是事儿!” 呵呵.不要被滚动条吓到,很多都是代码和图片.我没有分开写,不过上面给大家提供了目录,方 ...

  2. HTML5 Drop API

    转自:http://www.cnblogs.com/fsjohnhuang/p/3961066.html 一.前言    在HTML4的时代,各前端工程师为了实现拖拽功能可说是煞费苦心,初听HTML5 ...

  3. Three.js + HTML5 Audio API 打造3D音乐频谱,Let’s ROCK!

    继续玩味之前写的音乐频谱作品,将原来在Canvas标签上的 作图利用Three.js让它通过WebGL呈现,这样就打造出了一个全立体感的频谱效果了. 项目详情及源码 项目GitHub地址:https: ...

  4. HTML5 File API — 让前端操作文件变的可能

    前言 在 HTML5 File API 出现之前,前端对于文件的操作是非常有局限性的,大多需要配合后端实现.出于安全角度考虑,从本地上传文件时,代码不可能获取文件在用户本地的地址,所以纯前端不可能完成 ...

  5. 开大你的音响,感受HTML5 Audio API带来的视听盛宴

    话说HTML5的炫酷真的是让我爱不释手,即使在这个提到IE就伤心不完的年代.但话又说回来,追求卓越Web创造更美世界这样高的追求什么时候又与IE沾过边儿呢?所以当你在看本文并且我们开始讨论HTML5等 ...

  6. html5 history api

    1.html5 history api适用场景,个人理解最大的用处是配合ajax使用,使ajax拥有回退.前进的用户体验. 2.代码(dive into html5中的一个小例子) 1)fer.htm ...

  7. HTML5 history API实践

    一.history API知识点总结 在HTML4中,我们已经可以使用window.history对象来控制历史记录的跳转,可以使用的方法包括: history.forward();//在历史记录中前 ...

  8. Resumable.js – 基于 HTML5 File API 的文件上传

    Resumable.js 是一个 JavaScript 库,通过 HTML5 文件 API 提供,稳定和可恢复的批量上传功能.在上传大文件的时候通过每个文件分割成小块,每块在上传失败的时候,上传会不断 ...

  9. html5 drag api详解

    可以夸张点说,如果你不会拖拽,你不是一个合格的前端开发. 回想下,以前我们是怎么实现拖拽的,主要有以下几步: 1.目标元素绑定mousedown事件,记录下此时鼠标位置和拖拽元素的位置差,分别是 di ...

随机推荐

  1. PowerDesigner 生成的脚本取掉双引号

    建模工具PowerDesigner http://www.cnblogs.com/mcgrady/archive/2013/05/25/3098588.html 默认导出在带双引号,表名称后期使用的时 ...

  2. How do I list subversion repository's ignore settings

    If it is Windows and you are using TortoiseSVN, then right-click on a folder of the working copy, go ...

  3. StretchBlt

    StretchBlt  函数从源矩形中复制一个位图到目标矩形,必要时按目前目标设备设置的模式进行图像的拉伸或压缩以满足目标矩形的尺寸. 原型: BOOL StretchBlt( HDC hdcDest ...

  4. python portia

    docker run -i -t --rm -v <PROJECTS_FOLDER>:/app/data/projects:rw -p 9001:9001 scrapinghub/port ...

  5. eclipse里启动tomcat无法通过127.0.0.1访问

    在eclipse里面添加tomcat,再发布一个web项目进去,然后启动tomcat,日志显示tomcat在eclipse里面正常启动,hosts里面配置了ip跟域名的对应关系. 通过域名访问可以正常 ...

  6. C#泛型序列化困境

    [C#泛型序列化困境] 问题的起因是这样,有一个需求,将JsonArray转化为List,JsonArray中的元素均是string,此string可被转化为int.float.或维持string.我 ...

  7. Theoretical & Applied Mechanics Letters第2届编委会2015年度第1次全体编委会工作会议纪要(转自力学学会)

    2015年7月26日, Theoretical & Applied Mechanics Letters (TAML)第2届编委会在中国科学院力学研究所召开2015年第1次 全体编委工作会议.主 ...

  8. errorlevel 续1

    -------siwuxie095             常用 errorlevel 返回值:     backup 0 备份成功 1 未找到备份文件 2 文件共享冲突阻止备份完成 3 用户用 ct ...

  9. js获取不到动态添加的标签的值的解决方法

    遇到了js无法获得动态添加的标签的值,百度了一番,最后自己解决了问题,但是原理现在还不怎么明确. $("input[id='txtAttValue']").each(functio ...

  10. 二叉搜索树的后序遍历序列 (java)

    import java.util.*; public class Solution { public boolean VerifySquenceOfBST(int [] sequence) { if( ...