WebSocket - 一篇文章读懂websocket
一篇文章了解WebSocket
WebSocket 產生背景
在我們開發過程中使用最多的就是 HTTP協議,當我們想要獲取某些數據時由客戶端發起請求,服務端接受請求并返回相對應的數據。
但是這種單項請求方式存在一定的弊端,那就是只能由客戶端發起請求,服務端響應,服務端不能夠直接給客戶端發送數據。而在實際開發中我們往往會遇到這些情況:數據在不斷的發生變化,需要實時從服務器請求數據。例如:系統的實時運行日志、實時通信消息、系統的實時狀態等等。
如果我們繼續使用 http協議就需要定時請求,即常說的 ‘ 輪詢 ’。輪詢的效率較低,而且對于實時性并不是很友好,此時我們便需要使用到 WebSocket。
什么是WebSoket?
定義
WebSocket 是 html5 新增的一種協議,是一種網絡通信協議。WebSocket協議不是一種全新的協議,而是利用 HTTP協議來建立的一種協議。
WebSocket的連接過程
WebSocket的連接必須是客戶端發起,因為請求協議是一個標準的 http 協議,請求過程如下:
GET ws://localhost:3000/ws/chat HTTP/1.1 Host: localhost Upgrade: websocket Connection: Upgrade Origin: http://localhost:3000 Sec-WebSocket-Key: client-random-string Sec-WebSocket-Version: 13websocket 的請求與普通的 http 的請求存在以下幾種區別點:
- GET請求的地址不是類似/path/,而是以ws://開頭的地址;
- 請求頭Upgrade: websocket和Connection: Upgrade表示這個連接將要被轉換為WebSocket連接;
- Sec-WebSocket-Key是用于標識這個連接,并非用于加密數據;
- Sec-WebSocket-Version指定了WebSocket的協議版本。
當請求成功后,服務器會返回以下響應:
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: server-random-string服務器返回的響應中,應該注意以下幾點:
- 響應代碼:101 表示本次連接的http協議即將被更改,更改后的協議就是 upgrade:websocket 指定的 websocket協議
此時,一個完成的 websocket 連接已經建立成功,瀏覽器和服務器可以隨時通信,發送消息。
websocket連接的特點
websocket連接最大的特點就是 服務器 可以主動向 客戶端發送消息,客戶端也可以向服務器端發送消息,是真正平等的對話。
其他的特點如下:
客戶端的示例
// 建立websocket連接 var ws = new WebSocket("wss://echo.websocket.org");// websocket建立成功之后的回調函數 ws.onopen = function(evt) { console.log("Connection open ..."); ws.send("Hello WebSockets!"); };// websocket接受到數據后的回調函數 ws.onmessage = function(evt) {console.log( "Received Message: " + evt.data);ws.close(); };// websocket關閉后的回調函數 ws.onclose = function(evt) {console.log("Connection closed."); };從 API 的角度理解websocket
4-1 構造函數
**WebSocket()**構造函器會返回一個 WebSocket 對象
語法
var ws = new WebSocket(url [, protocols]);示例
var ws = new WebSocket('ws://localhost:8080');執行結果
執行構造函數后,客戶端會返回一個websocket對象的實例,并且客戶端和服務器端建立連接
4-2 屬性
(1)binaryType
作用
WebSocket.binaryType 返回websocket連接所傳輸二進制數據的類型。
語法
var binaryType = aWebSocket.binaryType;返回值
1) blob:傳輸的類型為 Blob
2)arraybuffer:傳輸類型為 arraybuffer
(2)bufferedAmount【只讀】
作用
是一個只讀屬性,用于返回當前websocket對象已經執行send方法后,還未發送到服務器的字節數。如果已經全部發送給服務器,則該值會被重置為0 , 如果連接斷開后還一直執行send方法,該值便會一直增加
語法
var bufferedAmount = ws.bufferedAmount;示例
var data = new ArrayBuffer(10000000); ws.send(data);if (ws.bufferedAmount === 0) {// 發送完畢 } else {// 發送還沒結束 }(3)extensions【只讀】
作用
返回服務器已選擇的擴展值,目前鏈接支持的擴展值只有空字符串或者一個協議列表
語法
var extensions = ws.extensions;(4)protocol【只讀】
作用
返回服務器端選中的子協議的名稱,這是在創建websocket連接時,在參數中指定的字符串
語法
var protocol = ws.protocol;(5)readState【只讀】
作用
返回當前連接的鏈接狀態
語法
var readyState = ws.readyState;返回值
- CONNECTING:值為0,表示正在連接。
- OPEN:值為1,表示連接成功,可以通信了。
- CLOSING:值為2,表示連接正在關閉。
- CLOSED:值為3,表示連接已經關閉,或者打開連接失敗。
(6)onopen
作用
創建連接成功后的回調函數
語法
ws.onopen = function(event) {console.log("WebSocket is open now."); };說明
如果一個實例對象想要創建多個open的回調事件,可使用 addEventListen綁定事件
ws.addEventListen('open' , funciton(event){console.log("創建監聽事件"); })(7)onclose
作用
連接關閉后的回調函數
語法
ws.onclose = function(event) {var code = event.code;var reason = event.reason;var wasClean = event.wasClean;// handle close event };ws.addEventListener("close", function(event) {var code = event.code;var reason = event.reason;var wasClean = event.wasClean;// handle close event });(8)onmessage
作用
連接接收到數據之后的回調函數
語法
ws.onmessage = function(event) {console.debug("WebSocket message received:", event.data); };(9)onerror
作用
連接發生錯誤之后的回調函數
語法
ws.onerror = function(event) {console.error("WebSocket error observed:", event); };(10)url【只讀】
作用
返回創建連接時url的絕對路徑
4-3 方法
(1)close()
作用
關閉 websocket 連接或連接嘗試,如果websocket連接已經關閉,該方法沒有任何作用
語法
WebSocket.close();(2)send()
作用
send方法將需要通過 WebSocket 鏈接傳輸至服務器的數據排入隊列
語法
WebSocket.send("Hello server!");可傳輸的數據類型
- 字符串
- ArrayBuffer
- Blob
- ArrayBufferView
從 實例 角度理解websocket - 發送消息通信
5-1 準備dom元素
<div id="box"><div class="messageWrap"><input class="form-control urlInput" id="url" type="text" placeholder='請輸入連接地址'><button class="btn btn-primary" id="open" onclick="openWS()">連接</button><button class="btn btn-danger" onclick="closeWS()">關閉</button><textarea placeholder="請輸入發送的數據" class="form-control msg" name="" id="message" cols="30" rows="10"></textarea><button id="send" class="form-control btn btn-success" onclick="sendMessage()">發送</button></div><div class="resultWrap"></div> </div>5-2 創建websocket對象
let myWebsocket = {ws: null ,init(url , event){// 判斷瀏覽器是否支持wsif ('WebSocket' in window){this.ws = new WebSocket( url );this.listenerEvent( event ) ;this.listenClose();}else {alert("當前瀏覽器不支持 websocket 通信");}},listenerEvent(event) {this.ws.onopen = function (e) {event.open(e);};this.ws.onmessage = function (e) {event.message(e);};this.ws.onclose = function (e) {event.close(e);};this.ws.onerror = function (e) {event.error(e);}},listenClose(){window.onbeforeunload = function () {this.ws.close();}window.onbeforeload = function () {this.ws.close();}} };5-3 使用websocket對象
// 事件配置 function open( event ){let a = `<p class="alert alert-success">已經成功建立連接啦,可以發送數據呦!</p>`;$(".resultWrap").append(a); } function close( event ){let a = `<p class="alert alert-secondary ">已關閉連接</p>`;$(".resultWrap").append(a); } function error( event ){let a = `<p class="alert alert-danger ">連接失敗</p>`;$(".resultWrap").append(a); } function message( event ){let data = event.data;let a = `<b>從服務器接收到的數據:</b>`+data;$(".resultWrap").append(a);} // 創建連接 function openWS(){myWebsocket.init($("#url").val(),{ open:open , close:close , error:error , message:message }) }// 關閉連接 function closeWS() {myWebsocket.ws.close(); }// 發送數據 function sendMessage(){myWebsocket.ws.send(document.querySelector("#message").value)let a = `<b style="color: #1e7e34">你向服務端發送:</b>`+ document.querySelector("#message").value;$(".resultWrap").append(a);$("#message").val(""); }5-4 運行效果
高級版 - websocket 心跳機制
使用背景
如果在連接后需要長時間保持連接,但又不是一直都在通信,可以在連接中添加心跳機制,每隔一段時間就從客戶端發送一個數據給后臺,后臺再返回一個數據給客戶端保持通信。
6-1 準備元素
同 5-1
6-2 創建含有心跳機制的websocket對象
// 心跳機制 let heartCheck = {timeout:600000,timeoutObj:null,serverTimeoutObj:null,reset(){clearTimeout(this.timeoutObj);clearTimeout(this.serverTimeoutObj);return this;},start: function(){let self = this;this.timeoutObj = setTimeout(function(){myWebsocket.ws.send("ping");let a = `<b style="color: #1e7e34">檢測心跳:ping</b>`;$(".resultWrap").append(a);self.serverTimeoutObj = setTimeout(function(){· myWebsocket.ws.close();}, self.timeout)}, this.timeout)} } // 含有心跳的websocket對象 let myWebsocket = {ws: null ,url:"",event: null ,init(url , event){try{if('WebSocket' in window){this.ws = new WebSocket( url );let a = `<b style="color: #1e7e34">再次連接</b>`;$(".resultWrap").append(a);this.url = url ;this.event = event;this.listenerEvent( event ) ;this.listenClose();}else{alert("您的瀏覽器不支持websocket協議,建議使用新版谷歌、火狐等瀏覽器,請勿使用IE10以下瀏覽器,360瀏覽器請使用極速模式,不要使用兼容模式!");}}catch(e){this.reconnect(url);console.log(e);}},listenerEvent(event) {let $this = this;$this.ws.onopen = function (e) {heartCheck.reset();heartCheck.start();event.open(e);};$this.ws.onmessage = function (e) {heartCheck.reset();heartCheck.start();event.message(e);};$this.ws.onclose = function (e) {event.close(e);$this.reconnect();};$this.ws.onerror = function (e) {$this.reconnect( $this.url );event.error(e);}},listenClose(){window.onbeforeunload = function () {this.ws.close();};window.onbeforeload = function () {this.ws.close();}},reconnect(){let $this = this;setTimeout(function () {$this.init($this.url , $this.event);}, 3000);}, };6-3 使用
同 5-3
參考鏈接
- 【廖雪峰官方網站】https://www.liaoxuefeng.com/wiki/1022910821149312/1103332447876608
- 【阮一峰教程】http://www.ruanyifeng.com/blog/2017/05/websocket.html
- 【MDN API】https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket
- https://www.cnblogs.com/fuqiang88/p/5956363.html
代碼演示
代碼下載演示:https://github.com/jianyaoo/js/tree/master/websoket
總結
以上是生活随笔為你收集整理的WebSocket - 一篇文章读懂websocket的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 解耦的重要性
- 下一篇: 微信登入及获取微信手机号