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)組成,例如因爲scheme(https、http)不一樣,則源不一樣。框架
跨源通訊經過 源來肯定發送者,這就使得接收方能夠忽略或者拒絕來自不可信源的消息。同時須要經過添加監聽事件來接受消息,以免被不可信應用程序的信息所幹擾。可是在使用外來消息時,即使是可靠的數據源,也一樣要謹慎,以防止內容注入。函數
在使用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
XMLHttpRequestLevel2是XMLHttpRequest的改進版本,主要涉及:跨源XMLHttpRequess和進度事件(Progress events)。
XMLHttpRequest僅限於同源通訊,XMLHttpRequestLevel2經過跨資源共享實現(Cross Origin Resource Sharing)跨源XMLHttpRequests。
在XMLHttpRequest中經過readystatechange事件來響應進度,可是其在某些瀏覽器中不被兼容。XMLHttpRequestLevel2用了一個有意義的名字Progress進度來命名進度事件。其進度事件的名稱主要有loadstart、progress、abort、error、load、loadend。經過對程序屬性設置回調函數,能夠實現對這些事件的監聽。
在使用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的訪問。