HTML5编程之旅 第2站 Communication

HTML5 Communication 初探 css

      本文主要探讨用于构建实时跨源通讯的两个模块:跨文档消息通讯(Cross Document Messaging)和XMLHttpRequestLevel2。经过这两个模块,咱们能够构建不一样域间进行安全通讯的Web应用。 html

1、跨文档消息通讯web

       出于安全方面的看的考虑,运行在同一浏览器中的框架、标签页、窗口间的通讯一直多受到严格的限制。可是现实中还存在一些合理的让不一样站点的内容能在浏览器内进行交互的需求,其中Mashup就是一个典型的例子,它是各类不一样应用的结合体。为了知足上述需求,引入了一种新的功能:跨文档消息通讯。其能够确保iframe、标签页、窗口间安全地进行跨源通讯。浏览器

    发送消息使用postMessage API,其示例代码以下:安全

chatFrame.contentWindow.postMessage(content,url);

    接受消息时,须要在页面中添加一个事件处理函数,当消息到达时,经过检查消息的来源来决定如何对这条消息如何处理,示例代码以下:
服务器

window.addEventListener("message",messageHandler,true);
    function messageHandler(e){
        switch(e.origin){//表示数据发送源
        case "friend.example.com":
            //处理消息
            processMessage(e.data);//发送方实际传送的消息
            break;
        default:
            //其余消息来源
            //消息被忽略。
    }
}

    postMessage API提供了一种交互方式,使得不一样源的iframe之间能够进行消息通讯。
网络

    HTML5经过引入源的感念对域安全进行了阐明和改进。源是网络上用来创建信任关系的地址的子集。源由规则(scheme)、主机(host)、端口(port)组成,例如因为schemehttpshttp)不一样,则源不一样。框架

    跨源通讯经过 源来肯定发送者,这就使得接收方能够忽略或者拒绝来自不可信源的消息。同时须要经过添加监听事件来接受消息,以免被不可信应用程序的信息所干扰。可是在使用外来消息时,即使是可靠的数据源,也一样要谨慎,以防止内容注入。函数

    在使用postMessage API时,须要遵循如下步骤:post

    一、检查浏览器是否支持

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

    二、发送消息

window.postMessage("Hello","xx.example.com");

第一个参数包含要发送的数据,第二个参数时消息传递的目的地。

若是要发送消息给iframe,则使用以下代码:

document.getElementById("iframe")[0].contentWindow.postMessage("Hello","xx.example.com");

    三、监听消息事件

window.addEventListener("message",messageHandler,true);
var originWhiteList = ["a.example.com","b.example.com","c.example.com"];
function messageHandler(e){
    if(checkWhiteList(e.origin)){
        processMessage(e.data);//发送方实际传送的消息
    }else{
        //忽略发送的消息
    }
}
 
function checkWhiteList(origin){
    for(var i = 0; i<originWhiteList.length; i++){
        if(origin === originWhiteList[i]){
            return true;
        }
    }
    return false;
}

 2、XMLHttpRequestLevel2 

XMLHttpRequestLevel2XMLHttpRequest的改进版本,主要涉及:跨源XMLHttpRequess和进度事件(Progress events)。

XMLHttpRequest仅限于同源通讯,XMLHttpRequestLevel2经过跨资源共享实现(Cross Origin Resource Sharing)跨源XMLHttpRequests

XMLHttpRequest中经过readystatechange事件来响应进度,可是其在某些浏览器中不被兼容。XMLHttpRequestLevel2用了一个有意义的名字Progress进度来命名进度事件。其进度事件的名称主要有loadstartprogressaborterrorloadloadend。经过对程序属性设置回调函数,能够实现对这些事件的监听。

在使用XMLHttpRequestLevel2时,须要遵循如下步骤:

    一、检查浏览器是否支持

var xhr = new XMLHttpRequest();
if(typeof xhr.withXredentials === undefined){
    //浏览器不支持XMLHttpRequest
}

    二、构建跨源请求

var crossOriginRequest = new XMLHttpRequest();
crossOriginRequest.open("GET","http://www.example.com",true);

在请求过程当中,务必确保可以监听到错误,以找出出错缘由,解决问题。

    三、使用进度事件

crossOriginRequest.onprogress = function(e){
    var total = e.total;
    var loaded = e.loaded;
    if(e.lengthComputable){
        //处理其余事情
    }
}
 
crossOriginRequest.upload..onprogress = function(e){
    var total = e.total;
    var loaded = e.loaded;
    if(e.lengthComputable){
        //处理其余事情
    }
}

3、postMessage API示例应用

以跨源聊天应用为例,来演示门户页面和聊天部件之间的交互。

    1、建立postMessagePortal.html页面

<!DOCTYPE html>    
    <head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>跨源通讯-WebChat</title>
    <link rel="stylesheet" href="styles.css">
    </head>
     
    <h1>跨源通讯门户</h1>
    <p><b>源</b>: http://portal.example.com:8080</p>
    状态 <input type="text" id="statusText" value="Online">
    <button id="sendButton">更改状态</button>
    <p>
    使用postMessage发送一个状态,以更新包含在此页面中的widgetiframe。
    </p>
    <iframe id="widget" src="http://chat.example.net:8080/communication/postMessageWidget.html"></iframe>
    <script>
        var targetOrigin = "http://chat.example.net:8080";
        var notificationTimer = null;
        function messageHandler(e){
            if(e.origin == targetOrigin){
                notify(e.data);
            }else{
                //忽略
            }
        }
        
        function sendString(s){
            document.getElementById("widget").contentWindow.postMessage(s,targetOrigin);
        }
        function notify(message){
            alert(message);
        }
        function sendStatus(){
            var statusText = document.getElementById("statusText").value;
            sendString(statusText);
        }
        function loadDemo(){
            document.getElementById("sendButton").addEventListener("click",sendStatus,true);
            sendStatus();
        }
        window.addEventListener("load",loadDemo,true);
        window.addEventListener("message",messageHandler,true);
    </script>

二、建立postMessageWidget.html

<!DOCTYPE html>
    <head>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>widget</title>
    <link rel="stylesheet" href="styles.css">
    </head>
    <h1>Widget iframe</h1>
    <p><b>源</b>: http://chat.example.net:8080</p>
    <p>经过门户设置状态为: <strong id="status"></strong> <p>
     
    <div>
        <input type="text" id="messageText" value="Widget notification.">
        <button id="actionButton">发送通知</button>
    </div>
     
    <script>
        var targetOrigin = "http://portal.example.com:8080";
        window.addEventListener("load",loadDemo,true);
        window.addEventListener("message",messageHandler,true);
         
        function loadDemo(){
            document.getElementById("actionButton").addEventListener("click",
            function() {
                var messageText = document.getElementById("messageText").value;
                sendString(messageText);
            }, true);
        }
         
        function messageHandler(e) {
            if (e.origin === "http://portal.example.com:8080") {
                document.getElementById("status").textContent = e.data;
            } else {
                // ignore messages from other origins
            }
        }
         
        function sendString(s) {
            window.top.postMessage(s, targetOrigin);
        }
    </script>


注意:第1、上述的两个页面须要部署到web服务器;第2、两个页面必须来自不一样的域。若是要在本机部署,则须要更改hosts文件,增长:

127.0.0.1 portal.example.com
127.0.0.1 chat.example.net

修改完成后,须要关闭浏览器,再次从新打开。

4、XMLHttpRequestLevel2示例应用

一、建立crossOriginUpload.html页面:

<!DOCTYPE html>
<head>
header(“Access-Control-Allow-Origin: *”); 
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>上传地理数据</title>
<link rel="stylesheet" href="styles.css">
</head>
<script>
 
    function loadDemo() {
        var dataElement = document.getElementById("geodata");
        dataElement.textContent = JSON.stringify(geoData).replace(",", ", ", "g");
     
        var xhr = new XMLHttpRequest()
        if (typeof xhr.withCredentials === undefined) {
            document.getElementById("support").innerHTML = "浏览器不支持跨源XMLHttpRequest";
        } else {
            document.getElementById("support").innerHTML = "浏览器支持跨源XMLHttpRequest";
        }
     
        var targetLocation = "http://geodata.example.net:8080/upload";
     
        function setProgress(s) {
            document.getElementById("progress").innerHTML = s;
        }
     
        document.getElementById("sendButton").addEventListener("click",
            function() {
                xhr.upload.onprogress = function(e) {
                    var ratio = e.loaded / e.total;
                    setProgress("已上传" + ratio + "%");
                }
    xhr.onprogress = function(e) {
    var ratio = e.loaded / e.total;
    setProgress("已下载" + ratio + "%");
    }
     
                xhr.onload = function(e) {
                    setProgress("完成");
                }
     
                xhr.onerror = function(e) {
                    setProgress("错误");
                }
     
                xhr.open("POST", targetLocation, true);
                geoDataString = dataElement.textContent;
                xhr.send(geoDataString);
            }, true);
     
    }
    window.addEventListener("load", loadDemo, true);
 
</script>
 
<h1>XMLHttpRequest Level 2</h1>
<p id="support"></p>
 
<h4>上传地理数据:</h4>
<textarea id="geodata">
</textarea>
</div>
 
<button id="sendButton">上传</button>
 
<script>
geoData = [[39.080018000000003, 39.112557000000002, 39.135261, 39.150458, 39.170653000000001, 39.190128000000001, 39.204510999999997, 39.226759000000001, 39.238483000000002, 39.228154000000004, 39.249400000000001, 39.249533, 39.225276999999998, 39.191253000000003, 39.167993000000003, 39.145685999999998, 39.121620999999998, 39.095761000000003, 39.080593, 39.053131999999998, 39.02619, 39.002929000000002, 38.982886000000001, 38.954034999999998, 38.944926000000002, 38.919960000000003, 38.925261999999996, 38.934922999999998, 38.949373000000001, 38.950133999999998, 38.952649000000001, 38.969692000000002, 38.988512999999998, 39.010652, 39.033088999999997, 39.053493000000003, 39.072752999999999], [-120.15724399999999, -120.15818299999999, -120.15600400000001, -120.14564599999999, -120.141285, -120.10889900000001, -120.09528500000002, -120.077596, -120.045428, -120.0119, -119.98897100000002, -119.95124099999998, -119.93270099999998, -119.927131, -119.92685999999999, -119.92636200000001, -119.92844600000001, -119.911036, -119.942834, -119.94413000000002, -119.94555200000001, -119.95411000000001, -119.941327, -119.94605900000001, -119.97527599999999, -119.99445, -120.028998, -120.066335, -120.07867300000001, -120.089985, -120.112227, -120.09790700000001, -120.10881000000001, -120.116692, -120.117847, -120.11727899999998, -120.14398199999999]];
</script>
 
<p>
    <b>状态: </b> <span id="progress">准备</span>
</p>

注意:部署web应用,运行crossOriginUpload.html页面时,可能会才出现以下的提示错误:

 

这是由于访问一页面的域与所请求的域非同源形成的。且浏览器是根据响应头的规则来肯定这个域是否同源能够接收。

所以咱们须要http://geodata.example.net:8080/upload在返回内容时,设置Header Access-Control-Allow-Origin,即:

Response.AddHeader("Access-Control-Allow-Origin","*") ;

浏览器在接收到服务器返回信息时,会检查响应头的Access-Control-Allow-Origin,它的值标识请求内容所容许的域。若是将服务器设置Access-Control-Allow-Origin*,代表该返回信息容许全部源访问。若是设置为具体的域,如http://xx.com,就代表除了同源外,只容许域来自xx.com的访问。

相关文章
相关标签/搜索