標籤:doctype 為什麼 utf-8 for event catch 超過 測試 protoc
====測試代碼:
==index.html
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Document</title></head><body> <div> abc </div></body><script type="text/javascript" src="js/websocket.js"></script><script src="js/client.js"></script></html>
==websocket.js
var lockReconnect = false; //避免ws重複串連var ws = null; // 判斷當前瀏覽器是否支援WebSocketvar wsUrl = null;var config = {};function socketLink(set) { config = set; wsUrl = config.url; createWebSocket(wsUrl); //串連ws}function createWebSocket(url) { try { if (‘WebSocket‘ in window) { ws = new WebSocket(url, ‘echo-protocol‘); } else if (‘MozWebSocket‘ in window) { ws = new MozWebSocket(url, ‘echo-protocol‘); } else { alert("您的瀏覽器不支援websocket") } initEventHandle(); } catch (e) { reconnect(url); console.log(e); }}function initEventHandle() { ws.onclose = function() { reconnect(wsUrl); console.log("llws串連關閉!" + new Date().toUTCString()); }; ws.onerror = function() { reconnect(wsUrl); console.log("llws串連錯誤!"); }; ws.onopen = function() { heartCheck.reset().start(); //心跳檢測重設 console.log("llws串連成功!" + new Date().toUTCString()); config.open(ws) }; ws.onmessage = function(event) { //如果擷取到訊息,心跳檢測重設 heartCheck.reset().start(); //拿到任何訊息都說明當前串連是正常的 config.msg(event.data,ws) };}// 監聽視窗關閉事件,當視窗關閉時,主動去關閉websocket串連,防止串連還沒斷開就關閉視窗,server端會拋異常。window.onbeforeunload = function() { ws.close();}function reconnect(url) { if (lockReconnect) return; lockReconnect = true; setTimeout(function() { //沒串連上會一直重連,設定延遲避免請求過多 createWebSocket(url); lockReconnect = false; }, 2000);}//心跳檢測var heartCheck = { timeout: 10000, //9分鐘發一次心跳 timeoutObj: null, serverTimeoutObj: null, reset: function() { clearTimeout(this.timeoutObj); clearTimeout(this.serverTimeoutObj); return this; }, start: function() { var self = this; this.timeoutObj = setTimeout(function() { //這裡發送一個心跳,後端收到後,返回一個心跳訊息, //onmessage拿到返回的心跳就說明串連正常 ws.send("ping"); console.log("ping!") self.serverTimeoutObj = setTimeout(function() { //如果超過一定時間還沒重設,說明後端主動斷開了 console.log("try=close") ws.close(); //這裡為什麼要在send檢測訊息後,倒計時執行這個代碼呢,因為這個代碼的目的時為了觸發onclose方法,這樣才能實現onclose裡面的重連方法
//所以這個代碼也很重要,沒有這個方法,有些時候發了定時檢測訊息給後端,後端逾時(我們自己設定的時間)後,不會自動觸發onclose方法。我們只有執行ws.close()代碼,讓ws觸發onclose方法
//的執行。如果沒有這個代碼,串連沒有斷線的情況下而後端沒有正常檢測響應,那麼瀏覽器時不會自動逾時關閉的(比如Google瀏覽器),Google瀏覽器會自動觸發onclose
//是在斷網的情況下,在沒有斷線的情況下,也就是後端響應不正常的情況下,瀏覽器不會自動觸發onclose,所以需要我們自己設定逾時自動觸發onclose,這也是這個代碼的
//的作用。
}, self.timeout) }, this.timeout) }}
心跳檢測的目的時什麼呢?
一個是為了定時發送訊息,使串連不逾時自動斷線,可能後端設了逾時時間就會自動斷線,所以需要定時發送訊息給後端,讓後端伺服器知道串連還在通訊息不能斷。
二來是為了檢測在正常還串連著的情況下,判斷後端是否正常,如果我們發了一個定時檢測給後端,後端按照約定要下發一個檢測訊息給前端,這樣才是正常的。
可是如果後端沒有正常下發呢,我們就要設定一下逾時要重連了,我們把重連寫在了onclose裡面,當時正常串連的情況下,逾時未能響應檢測訊息的情況下,瀏覽器不會自動斷掉觸發onclose,所以需要我們手動觸發,也就是在逾時裡寫一個ws.close()讓ws關閉觸發onclose方法,實現重連。
==瀏覽器會觸發onclose的情況是斷網斷線的情況下,當時正常串連還未斷線,瀏覽器時不會自動觸發onclose的,所以就有逾時手動觸發onclose的必要。
self.serverTimeoutObj = setTimeout(function() { //如果超過一定時間還沒重設,說明後端主動斷開了 console.log("try=close") ws.close(); //這裡為什麼要在send檢測訊息後,倒計時執行這個代碼呢,因為這個代碼的目的時為了觸發onclose方法,這樣才能實現onclose裡面的重連方法 //所以這個代碼也很重要,沒有這個方法,有些時候發了定時檢測訊息給後端,後端逾時(我們自己設定的時間)後,不會自動觸發onclose方法。我們只有執行ws.close()代碼,讓ws觸發onclose方法 //的執行。如果沒有這個代碼,串連沒有斷線的情況下而後端沒有正常檢測響應,那麼瀏覽器時不會自動逾時關閉的(比如Google瀏覽器),Google瀏覽器會自動觸發onclose //是在斷網的情況下,在沒有斷線的情況下,也就是後端響應不正常的情況下,瀏覽器不會自動觸發onclose,所以需要我們自己設定逾時自動觸發onclose,這也是這個代碼的 //的作用。 }, self.timeout)
ws.onopen = function() { heartCheck.reset().start(); //心跳檢測重設 在open的時候觸發心跳檢測 console.log("llws串連成功!" + new Date().toUTCString()); config.open(ws) }; ws.onmessage = function(event) { //如果擷取到訊息,心跳檢測重設 heartCheck.reset().start(); //拿到任何訊息都說明當前串連是正常的 //如果後端有下發訊息,那麼就會重設初始化心跳檢測,除非逾時沒下發,那麼就會觸發onclose
//然後觸發重連
config.msg(event.data,ws) };
==client.js
var number=0;var config = { url: ‘ws://localhost:8080/‘, open: (ws) => { function sendNumber() { if (ws.readyState === ws.OPEN) { number = number+1; ws.send(number.toString()); setTimeout(sendNumber, 1000); } } sendNumber() }, msg: (data) => { console.log(data, "msg") }}socketLink(config)
==node 後端測試代碼:
#!/usr/bin/env nodevar WebSocketServer = require(‘websocket‘).server;var http = require(‘http‘);var server = http.createServer(function(request, response) { console.log((new Date()) + ‘ Received request for ‘ + request.url); response.writeHead(404); response.end();});server.listen(8080, function() { console.log((new Date()) + ‘ Server is listening on port 8080‘);});wsServer = new WebSocketServer({ httpServer: server, // You should not use autoAcceptConnections for production // applications, as it defeats all standard cross-origin protection // facilities built into the protocol and the browser. You should // *always* verify the connection‘s origin and decide whether or not // to accept it. autoAcceptConnections: false});function originIsAllowed(origin) { console.log(origin,"origin") // put logic here to detect whether the specified origin is allowed. return true;}wsServer.on(‘request‘, function(request) { if (!originIsAllowed(request.origin)) { // Make sure we only accept requests from an allowed origin request.reject(); console.log((new Date()) + ‘ Connection from origin ‘ + request.origin + ‘ rejected.‘); return; } var connection = request.accept(‘echo-protocol‘, request.origin); console.log((new Date()) + ‘ Connection accepted.‘); connection.on(‘message‘, function(message) { if (message.type === ‘utf8‘) { console.log(‘Received Message: ‘ + message.utf8Data); //connection.sendUTF(message.utf8Data); //注釋掉是為了測試前端在沒後端響應卻串連著的情況下,是什麼反應。 } else if (message.type === ‘binary‘) { console.log(‘Received Binary Message of ‘ + message.binaryData.length + ‘ bytes‘); connection.sendBytes(message.binaryData); } }); connection.on(‘close‘, function(reasonCode, description) { console.log((new Date()) + ‘ Peer ‘ + connection.remoteAddress + ‘ disconnected.‘); });});
javascript websocket 心跳檢測機制介紹