就目前而言,WebSocket是最好的Web通訊解決方案了。可是IE從10纔開始兼容它,對於目前大量IE8存在的市場,原生的WebSocket顯然不太實用,咱們須要低版本兼容的解決方案。因而我模擬WebSocket在瀏覽器上的行爲,用AS3寫了個兼容的版本。
內容有點多,這篇只把演示給搞定,至於AS的源碼就丟到下一篇了。下面是效果圖:
演示下載地址: WebSocket兼容到低版本瀏覽器(演示實例)
頁面代碼比較簡單,用法和正常的WebSocket基本同樣,只是引用了WebSocket.js這個文件來兼容低版本瀏覽器。固然還有個WebSocket.swf須要放在與頁面相同的目錄下。 <script src="WebSocket.js"></script>
服務器程序使用NodeJS代碼,隨手寫的聊天室功能,僅僅爲了實現功能而已,做爲演示代碼不要吐槽考慮的不夠周全。裏面的 decodeDataFrame 和 encodeDataFrame 在以前的文章中有出現過,這裏就不貼出來了。因爲須要兼容AS版,因此服務器程序須要比普通的WebSocket多一個AS的域安全驗證的步驟。這是關鍵所在,若是使用現成的WebSocket庫之類的東西可能得稍微修改源碼才能兼容AS版。
<script>
onload=function(){
var ws=new WebSocket("ws://127.0.0.1:8000");
ws.onopen=function(){
//握手成功
send.removeAttribute("disabled");
send.value="發送";
};
ws.onmessage=function(e){
//收到消息,放到頁面上
var dl,dt,dd,o=eval("("+e.data+")");
dl=document.createElement("dl");
dt=document.createElement("dt");
dd=document.createElement("dd");
dt.innerHTML=o.client;
dd.appendChild(document.createTextNode(o.content));
dl.appendChild(dt);
dl.appendChild(dd);
wall.appendChild(dl);
wall.scrollTop=1E8; //滾動條移到底部
};
send.onclick=function(){
//發送消息
if(!message.value)return alert("請輸入內容");
ws.send(message.value);
message.value="";
};
};
</script>
<style>
dl {margin:3px 10px;font:14px/20px Consolas,微軟雅黑;}
dt {color:blue;}
#wall {
border:1px solid #CCC;width:200px;height:200px;
overflow-y:auto;margin-bottom:10px;
}
</style>
<div id="wall"></div>
<input id="message" />
<input type="button" value="鏈接中···" id="send" disabled />var crypto=require('crypto');
Flash握手就是AS的域安全驗證,這個在以前的文章「 使用AS直接與服務器TCP通訊 」中有詳細的說過,其實就是加載一個策略文件給它。把這個過程嵌入到WebSocket的握手以前就行。
var fs=require('fs');
var WS='258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
var pool=[]; //鏈接池
require('net').createServer(function(o){
var key;
o.on('data',function(e){
if(!key){
var data=e.toString();
//Flash握手
if(data=='<policy-file-request/>\0')
return fs.readFile('policy.txt',function(err,data){
o.write(data+'\0');
});
//WebSocket握手
if(key=data.match(/Sec-WebSocket-Key: (.+)|$/)[1])
key=crypto.createHash('sha1').update(key+WS).digest('base64'),
o.write([
'HTTP/1.1 101 Switching Protocols',
'Upgrade: websocket',
'Connection: Upgrade',
'Sec-WebSocket-Accept: '+key
].join('\r\n')+'\r\n\r\n');
}else{
//解析數據
var frame=decodeDataFrame(e);
//文本幀
if(frame.Opcode==1){
//轉義數據
var content=frame.PayloadData.replace(/\W/g,function(e){
e=e.charCodeAt(0).toString(16);
if(e.length==3)e='0'+e;
return '\\'+(e.length>2?'u':'x')+e;
}),client=o.remoteAddress+":"+o.remotePort,buffer;
//包裝成JSON格式,並作成一個數據幀
buffer=encodeDataFrame({
FIN:1,Opcode:1,
PayloadData:'{"client":"'+client+'","content":"'+content+'"}'
});
//對全部鏈接廣播數據
for(i=0;i<pool.length;i++)pool[i].write(buffer);
};
};
});
//斷開時從鏈接池中移除
o.on("close",function(){
for(i=0;i<pool.length;i++)if(pool[i]==o)pool.splice(i,1);
});
//放入鏈接池中
pool.push(o);
}).listen(8000);
WebSocket.js的代碼就不貼出來講明瞭。它負責構造一個相似原生WebSocket的接口的功能,裏面會對不兼容WebSocket的瀏覽器加載WebSocket.swf來使之兼容。
這個程序也是最近剛寫的,存在漏洞在所不免,若是實用的話之後將慢慢完善它。html