WebSocket 是一種網絡通訊協議。RFC6455定義了它的通訊標準。javascript
WebSocket 是 HTML5 開始提供的一種在單個 TCP 鏈接上進行全雙工通信的協議。html
咱們知道,傳統的HTTP協議是無狀態的,每次請求(request)都要由客戶端(如 瀏覽器)主動發起,服務端進行處理後返回response結果,而服務端很難主動向客戶端發送數據;這種客戶端是主動方,服務端是被動方的傳統Web模式 對於信息變化不頻繁的Web應用來講形成的麻煩較小,而對於涉及實時信息的Web應用卻帶來了很大的不便。vue
所以,隨着HTML5的誕生,一種新的通訊協議應運而生---WebSocket,他最大的特色就是服務端能夠主動向客戶端推送消息,客戶端也能夠主動向服務端發送消息,實現了真正的平等。java
舉個例子:如帶有即時通訊、實時數據、訂閱推送等功能的應用。在WebSocket規範提出以前,開發人員若要實現這些實時性較強的功能,常常會使用折衷的解決方法:ajax輪詢(最原始的實現實時Web應用的解決方案)web
ajax輪詢的原理:ajax輪詢的原理很是簡單,讓瀏覽器隔個幾秒就發送一次請求,詢問服務器是否有新信息。明顯地,這種方法會致使過多沒必要要的請求,浪費流量和服務器資源。
場景再現:
客戶端:有沒有新信息(Request)
服務端:沒有(Response)
客戶端:有沒有新信息(Request)
服務端:沒有。。(Response)
客戶端:有沒有新信息(Request)
服務端:你好煩啊,沒有啊。。(Response)
客戶端:有沒有新消息(Request)
服務端:有啦,給你。(Response)
客戶端:有沒有新消息(Request)
服務端:。。。。。沒。。。。沒。。。沒有(Response) ---- loopajaxwebsocket的原理:當服務器完成協議升級後(HTTP->Websocket),服務端就能夠主動推送信息給客戶端啦。
場景再現:
客戶端:我要創建Websocket協議,須要的服務:chat,Websocket協議版本:17(HTTP Request)
服務端:確認,已升級爲Websocket協議(HTTP Protocols Switched)
客戶端:麻煩你有信息的時候推送給我噢。。
服務端:好的,有的時候會告訴你的。
服務端:balabalabalabala
服務端:哈哈哈哈哈啊哈哈哈哈
服務端:笑死我了哈哈哈哈哈哈哈瀏覽器
(1)創建在 TCP 協議之上,服務器端的實現比較容易。服務器
(2)與 HTTP 協議有着良好的兼容性。默認端口也是80和443,而且握手階段採用 HTTP 協議,所以握手時不容易屏蔽,能經過各類 HTTP 代理服務器。websocket
(3)數據格式比較輕量,性能開銷小,通訊高效。網絡
(4)能夠發送文本,也能夠發送二進制數據。
(5)沒有同源限制,客戶端能夠與任意服務器通訊。
(6)協議標識符是ws
(若是加密,則爲wss
),服務器網址就是 URL。
瀏覽器經過 JavaScript 向服務器發出創建 WebSocket 鏈接的請求,鏈接創建之後,客戶端和服務器端就能夠經過 TCP 鏈接直接交換數據。當你獲取 WebSocket 鏈接後,你能夠經過 send() 方法來向服務器發送數據,並經過 onmessage 事件來接收服務器返回的數據。
// url, 指定鏈接的 URL
// protocol 是可選的,指定可接受的子協議。
let Socket = new WebSocket(url, [protocol] );
複製代碼
假設咱們建立了一個Socket對象
屬性 | 描述 |
---|---|
Socket.readyState | 只讀屬性 readyState 表示鏈接狀態,能夠是如下值: 0 - 表示鏈接還沒有創建。 1 - 表示鏈接已創建,能夠進行通訊。 2 - 表示鏈接正在進行關閉。 3 - 表示鏈接已經關閉或者鏈接不能打開。 |
Socket.bufferedAmount | 只讀屬性 bufferedAmount 已被 send() 放入正在隊列中等待傳輸,可是尚未發出的 UTF-8 文本字節數。 |
假設咱們建立了一個Socket對象
事件 | 事件處理程序 | 描述 |
---|---|---|
open | Socket.onopen | 鏈接創建時觸發 |
message | Socket.onmessage | 客戶端接收服務端數據時觸發 |
error | Socket.onerror | 通訊發生錯誤時觸發 |
close | Socket.onclose | 鏈接關閉時觸發 |
假設咱們建立了一個Socket對象
方法 | 描述 |
---|---|
Socket.send() | 使用鏈接發送數據 |
Socket.close() | 關閉鏈接 |
【1】原生JavaScript實現WebSocket鏈接
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <style> </style> <body> <input id="text" type="text" /> <button onclick="send()">發送消息</button> <button onclick="closeWebSocket()">關閉WebSocket鏈接</button> <div id="message"></div> <script> let websocket = null; //判斷當前瀏覽器是否支持WebSocket if ('WebSocket' in window) { websocket = new WebSocket("ws://localhost:8080/websocket"); } else { alert('當前瀏覽器不支持websocket!') } //鏈接發生錯誤的回調方法 websocket.onerror = function () { console.log("WebSocket鏈接發生錯誤"); }; //鏈接成功創建的回調方法 websocket.onopen = function () { console.log("WebSocket鏈接成功"); } //接收到消息的回調方法 websocket.onmessage = function (event) { document.getElementById('message').innerHTML += event.data + '<br/>'; } //鏈接關閉的回調方法 websocket.onclose = function () { console.log("WebSocket鏈接關閉"); } //監聽窗口關閉事件,當窗口關閉時,主動去關閉websocket鏈接,防止鏈接還沒斷開就關閉窗口,server端會拋異常。 window.onbeforeunload = function () { closeWebSocket(); } //關閉WebSocket鏈接 function closeWebSocket() { websocket.close(); } //發送消息 function send() { let message = document.getElementById('text').value; websocket.send(message); } </script> </body> </html>複製代碼
【2】在vue項目中實現WebSocket鏈接
<template> <div> <el-input v-model="params" clearable/> <el-button type="primary" @click="send">發消息</el-button> </div> </template> <script> export default { data() { return { params: '', path: "ws://localhost:8080/websocket", socket: "" } }, mounted() { // 初始化 this.init() }, destroyed() { // 銷燬監聽 this.socket.onclose = this.close }, methods: { init: function () { if (typeof (WebSocket) === "undefined") { console.log("您的瀏覽器不支持socket") } else { // 實例化socket this.socket = new WebSocket(this.path) // 監聽socket鏈接成功回調 this.socket.onopen = this.open // 監聽socket鏈接失敗回調 this.socket.onerror = this.error // 監聽後臺返回的socket消息 this.socket.onmessage = this.getMessage } }, open: function () { console.log("socket鏈接成功") }, error: function () { console.log("鏈接錯誤") }, getMessage: function (msg) { console.log(msg.data) }, send: function () { this.socket.send(params) }, close: function () { console.log("socket已經關閉") } } } </script>複製代碼