WebSocket 基本介紹及使用筆記

WebSocket 基本介紹及使用筆記

WebSocket前端得懂一點

最近遇到的一個案子,需要做一個像聊天室的功能,因為有幾位後端之前有研究SignalR,因此就是他們給了Augutsut一段範例碼後,Augustus就拿來套用而已,沒有說很了解。

後來漸漸被提到這個聊天室想要新增很多功能,大家初步討論了一下,都說需要用到WebSocket,不然前端就要傻傻的一直POST給Server。

因為之後會實際應用,就決定來看一下WebSocekt API,並整理成這篇筆記文,之後要用的時候方便查找。


WebSocket重點心智圖

Google了一下MDN跟菜鳥教程後,把吸收到的WebSocket基本應用整理成了一個心智圖,如下:

WebSocket重點心智圖(點擊看原圖)
WebSocket重點心智圖(點擊看原圖)

以下就是實際來使用一下。


用 Node.js 建一個簡單的 WebSocket Server

因為WebSocekt的一個特色就是Server可以主動發訊息給Client端,因此就必須要建立一個WebSocket Server才能夠測試。

Node.js有一個「WS」的套件,可參考官方說明:ws: a Node.js WebSocket library

安裝 ws

新增一個資料夾,用終端機開啟後輸入:npm init -y,按下enter。

接著再輸入:npm install ws,按下enter,就安裝完成了。

建立WS Server基本程式碼

這段直接copy說明文件的,新增一個index.js檔案,貼上以下程式碼:

const WebSocket = require('ws');
 
const wss = new WebSocket.Server({
  port: 8080
});

wss.on('connection', function connection(ws) {
  console.log('server connection')
  ws.on('message', function incoming(message) {
    console.log('received: %s', message);
  });
  ws.send('something');
});

因為Augustus有裝nodemon,因此在終端機輸入:nodemon index.js,按下enter,ws server就on起來了。

成功的話,我們建立出的WS Server URL就會是這樣:

ws://localhost:8080/

當client端連上後,就會看見終端機印出訊息,像這樣:

成功連結後印出的訊息
成功連結後印出的訊息

前端連結WebSocket

建立好了WebSocket Server,接著就可以開始實做前端連結的部份。

1 建立WebSocket

建立WebSocket的程式碼:

var ws = new WebSocket(url, [protocol]);

url 為必填,就是要填WS Server URL,像我們上一段最後建立的ws://localhost:8080/ 這樣。

protocol 為選填,有多個的話可以寫成陣列。MDN上面針對這個值的解譯是:

一個表示協定的字串或者是一個表示協定的字串構成的陣列。這些字串可以用來指定子協定,因此一個伺服器可以實作多個 WebSocket 子協定(舉例來說,你可以讓一個伺服器處理不同種類的互動情形,各情形以 protocol 分別)。若不指定協定字串則預設值為空字串。

建立完WebSocket後,我們可以 console.log(ws) 看一下有什麼:

console.log(ws)
console.log(ws)

readyState,連結WS Server的回應碼,總共有4碼,代表意思如下:

  • 0 – 表示連接尚未建立。
  • 1 – 表示連接已建立,可以進行通信。
  • 2 – 表示連接正在進行關閉。
  • 3 – 表示連接已經關閉或者連接不能打開。

所以像上面截圖中顯示的是「1」,代表成功連結上了WS Server。

bufferedAmount,代表client端要傳給server的訊息已被send()放入正在隊列中等待傳輸,但是還沒有發出。

onopenonerroroncloseonmessage,這4個是連接WS Server後會有的事件,介紹於下一段。


2 監聽WebSocket事件

當連結上WS Server後,server就可以主動發訊息給前端,前端這邊不用一直POST去查有沒有什麼更新,只要監聽server有沒有發新的訊息來就可以了。

WebSocket的事件共有4個:onopen、onerror、onclose、onmessage。

open

跟WS Server連接建立時會觸發:

ws.addEventListener('open', function() {
  console.log('連結建立成功。')
})

error

通信發生錯誤時觸發。

close

關閉跟WS Server的連線時觸發:

ws.addEventListener('close', function() {
  console.log('連結關閉,咱們下次見~')
})

message

收到server發來的訊息時觸發,這是最重要的一個事件,WebSocket優秀的地方就在這,可以監聽由server主動發來的訊息。

ws.addEventListener('message', function(e) {
  var msg = JSON.parse(e.data);
  console.log(msg)
})

這個function一整個跟postMessage好像,所以看到也不會覺得陌生。

之所以要將傳來的e.data JSON.parse,原因是WS Server傳來的格式會是字串,如果server傳來的格式直接是JSON未轉成字串的話,前後端都會報錯。

因為MDN特地標了一句「Firefox 目前只支援字串傳送」,所以實際要應用時,建議不論前後端都傳字串就好,畢竟Firefox是有一定市佔率的。

Augustus這邊直接在Node.js的部份加入一個setTimeout 10秒後傳個訊息出來:

wss.on('connection', function connection(ws) {
  var data = { name: "Augustus", blog: "Let's Write" }
  setTimeout(function() {
    ws.send(JSON.stringify(data));
  }, 10000);
});

之後在瀏覽器上等了10秒就有成功看到,代表WebSocket真的可以讓server主動發訊息到前端這。

成功看見訊息
成功看見訊息

3 client端發訊息給WS Server

WebSocket是讓前後端可以互通訊息的,因此除了接收由後端來的訊息,前端也可以主動發訊息給後端。

WebSocket API,methods有2個:sendclose

send就是發訊息,close就是關閉跟WS Server的連結。

send

這邊一樣前端10秒後發個訊息出去,WS Server監聽一個on message的事件。

前端 發訊息:

setTimeout(function() {
  var testMsg = {name: "Augustus", blog: "Let's Write"};
  ws.send(JSON.stringify(testMsg))
}, 10000)

後端 收訊息:

wss.on('connection', function connection(ws) {
  ws.on('message', function incoming(message) {
    console.log(JSON.parse(message));
  });
});

測試後,終端機成功看到訊息:

後端收到前端訊息
後端收到前端訊息

close

前端如果要主動斷開跟WS Server的連結,就是用close。

這邊一樣寫一個在10秒後close,並且加一個監聽close的事件:

ws.addEventListener('close', function(e) {
  console.log(e)
})
setTimeout(function() {
  ws.close()
}, 5000)

最後就會看到印出來的訊息是這樣:

close的console.log(點擊看原圖)
close的console.log(點擊看原圖)

筆記後心得

這篇是對WebSocket API的筆記整理,實際應用上比較多的情況是用在聊天室,所以後端收到message後,要再主動把收到的訊息發給所有有連結的前端,才能讓聊天室的訊息都同步。

所以後端的朋友責任會重一些,也因此才會有相應的套件產生吧?


參考資源

製作 WebSocket 客戶端應用程式

HTML5 WebSocket

ws: a Node.js WebSocket library

Summary
WebSocket 基本介紹及使用筆記
Article Name
WebSocket 基本介紹及使用筆記
Augustus
Let's Write
Let's Write
Publisher Logo
訂閱
通知
guest
0 Comments
Inline Feedbacks
看所有留言