Websocket - 實作一個簡單的聊天室 (+ Node.js)

先備知識 & 環境:

  • Node.js
  • 基本的 JavaScript 應用
  • 略知 WebSocket 概念

Server 端 (Node.js)

  • 啟一個 npm 專案並安裝套件
    • npm init -y
    • npm install express
    • npm install ws
  • 建立 js 檔(eg. server.js)

server.js

//import express 和 ws 套件
const express = require('express')
const SocketServer = require('ws').Server
const PORT = 3000 //指定 port

//創建 express 物件,綁定監聽  port , 設定開啟後在 console 中提示
const server = express().listen(PORT, () => {
    console.log(`Listening on ${PORT}`)
})
//將 express 交給 SocketServer 開啟 WebSocket 的服務
const wss = new SocketServer({ server })
//當有 client 連線成功時
wss.on('connection', ws => {
  console.log('Client connected')
  // 當收到client消息時
  ws.on('message', data => {
    // 收回來是 Buffer 格式、需轉成字串
    data = data.toString()  
    console.log(data) // 可在 terminal 看收到的訊息

    /// 發送消息給client 
    ws.send(data)

    /// 發送給所有client: 
    let clients = wss.clients  //取得所有連接中的 client
    clients.forEach(client => {
        client.send(data)  // 發送至每個 client
    })
  })
  // 當連線關閉
  ws.on('close', () => {
    console.log('Close connected')
  })
})
  • 運行 node server.js (若有安裝 nodemon 以 nodemon server.js 執行)

    nodemon 能熱更新 ,修改運行中的 server.js 時不用重啟即生效。

Client 端

  • 建立 html 檔(eg. index.html)
  • 單純的頁面有 input 輸入框、submit 按鈕、能顯示文字的區塊即可

index.html (style 略)

<textarea id="txtShow" disabled></textarea>
<input id="txtInput" type="text">
<button id="btnSend">送出</button>

JavaScript

document.addEventListener("DOMContentLoaded", event => { 
  let keyinDom = document.querySelector('#txtInput')
  let showDom = document.querySelector('#txtShow')

  document.querySelector("#btnSend").addEventListener('click',() => {
    let txt = keyinDom.value;
    ws.send(txt);
  })

  // 建立 WebSocket (本例 server 端於本地運行)
  let url = 'ws://localhost:3000'
  var ws = new WebSocket(url)
  // 監聽連線狀態
  ws.onopen = () => {
    console.log('open connection')
  }
  ws.onclose = () => {
    console.log('close connection');
  }
  //接收 Server 發送的訊息
  ws.onmessage = event => {
    let txt = event.data
    if (!showDom.value) showDom.value = txt
    else showDom.value = showDom.value + "\n" + txt
    keyinDom.value = ""
  }
});

預覽

  • 透過 WebSocket 即時傳遞文字

  • 開啟 devTool 觀察 WS 的資料往返

    Image

這樣就完成在本地簡單的 server 端 + client 端的 WebSocket 互動嚕!


小筆記 常用的基本語法 - Client 端

  • new WebSocket 建立連線

    var ws = new WebSocket('wss://...')
  • 監聽 WebSocket 的連線事件

    // 監聽 連線開啟時...
    ws.onopen = () => {
      ...
    }
    // 監聽 連線關閉時...
    ws.onclose = () => {
      ...
    }
    // 監聽 收到消息時
    ws.onmessage = event => {
      ...  // 取內容: event.data
    }
    // 監聽 錯誤時
    ws.onerror = event => {
      ...
    }
  • 發送消息

    ws.send('xxxx')
  • 關閉連線

    ws.close()
  • 取連線狀態

    ws.readyState
    // 0 = CONNECTING、1 = OPEN、2 = CLOSING、3 = CLOSED

Ref

- [WebSocket | MDN](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)

- [WebSocket readyState | MDN](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState)