Home (後端)Websocket with Node.js
Post
Cancel

(後端)Websocket with Node.js

Node.js 後端應用

這篇主要要介紹 Node.js 後端的開發,使用 Websocket 做為例子,為了整體完整性也為了讓你可以直接將 code 複製下來 rework, 因此也會提供前端 html 的部分,但 html 部分你可以放在任意的 web server, 不一定要跟 server 的 code 放在一起。

現在人的生活完全離不開通訊軟體,像是 Line, WeChat..等,這些通訊軟體基本上都是基於 WebSocket,再搭配其他技術(如 REST API、長輪詢、消息隊列)來處理不同的需求和功能。

下面就來介紹一下 Websocket

Websocket 介紹

WebSocket 是一種通信協議,旨在實現全雙工(雙向)通信,允許客戶端和伺服器在單個 TCP 連接上持續交換數據。與 HTTP 通信的請求-回應模式不同,WebSocket 在建立連接後,雙方可以隨時發送和接收數據,而不需要每次都重新建立連接。

WebSocket 的特性

  1. 持續連接:WebSocket 連接建立後,無需重複建立新連接,減少了頻繁握手的延遲。
  2. 雙向通信:伺服器可以主動推送數據到客戶端,而不需要客戶端發送請求,實現實時互動。
  3. 節省資源:因為持續連接,所以相比傳統的 HTTP 請求,WebSocket 減少了頻繁的 HTTP 頭部開銷和連接重建,尤其適合需要實時數據的應用。

WebSocket 的應用場景

  1. 即時聊天:客戶端和伺服器之間的消息能夠在極低延遲下傳輸,允許雙方即時通訊。WebSocket 的雙向通信特性非常適合聊天應用。
  2. 多人在線遊戲:遊戲中的玩家狀態更新需要實時同步到其他玩家,WebSocket 可以確保即時的狀態更新。
  3. 實時協作工具:如 Google Docs 這樣的協作工具,允許多個用戶同時編輯文檔,並即時同步變更給所有用戶。

Websocket with Node.js

以下示範如何使用 4 個檔案建立 websocket

Desktop View

Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 使用官方的 Node.js Docker 映像
FROM node:hydrogen-alpine3.20

# 設定工作目錄
WORKDIR /app

# 複製 package.json 和 package-lock.json (如果有)
COPY package*.json ./

# 安裝依賴
RUN npm install

# 複製所有文件到工作目錄
COPY . .

# 開放端口(假設使用的是 8080 端口)
EXPOSE 8080

# 啟動應用程式
CMD ["node", "server.js"]

package.json(這邊主要使用 ws 這個模組實現 websocket)

1
2
3
4
5
6
7
8
9
10
11
12
{
  "name": "my-nodejs-app",
  "version": "1.0.0",
  "description": "A simple Node.js web server",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "ws": "^8.18.0"
  }
}

server.js(啟動 WebSocket 服務)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// server.js
const WebSocket = require('ws');

// 創建 WebSocket 伺服器,並綁定到 HTTP 伺服器或端口
const wss = new WebSocket.Server({ port: 8080 });

// 當有客戶端連接時觸發
wss.on('connection', (ws) => {
    console.log('客戶端已連接');

    // 當接收到訊息時觸發
    ws.on('message', (message) => {
        console.log(`收到訊息: ${message}`);

        // 廣播訊息給所有已連接的客戶端
        wss.clients.forEach(client => {
            if (client.readyState === WebSocket.OPEN) {
                client.send(message);
            }
        });
    });

    // 傳送歡迎訊息給新客戶端
    ws.send('歡迎來到聊天室!');
});

console.log('WebSocket 伺服器在 ws://localhost:8080 上運行');

index.html (client 端去連結 websocket server 做通訊)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!-- index.html -->
<!DOCTYPE html>
<html lang="zh-TW">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>即時聊天室</title>
</head>

<body>
    <h1>即時聊天室</h1>
    <div id="chat"></div>
    <input type="text" id="messageInput" placeholder="輸入訊息...">
    <button id="sendButton">發送</button>

    <script>
        const ws = new WebSocket('ws://localhost:8080');

        // 當收到訊息時,將其顯示在聊天室中
        ws.onmessage = (event) => {
            // 如果是 Blob 物件,需將其轉換為文字
            if (event.data instanceof Blob) {
                event.data.text().then(text => {
                    displayMessage(text);
                });
            } else {
                displayMessage(event.data);
            }
        };

        // 顯示訊息的函數
        function displayMessage(message) {
            const chat = document.getElementById('chat');
            chat.innerHTML += `<p>${message}</p>`;
        }

        // 當點擊發送按鈕時,將訊息發送給伺服器
        document.getElementById('sendButton').onclick = () => {
            const message = document.getElementById('messageInput').value;
            ws.send(message);
            document.getElementById('messageInput').value = ''; // 清空輸入框
        };
    </script>
</body>

</html>

執行結果

在 container run 起 server, 這時可以看到 websocket 的服務已經啟動了

Desktop View

開兩個 client 去連 websocket 做通訊

Desktop View

websocket 被兩個 client 做連線

Desktop View

兩個 client 發訊息

Desktop View

websocket server 收到訊息後,轉發給所有 client

Desktop View

一樣,檔案都附上去了,有興趣的自己試一下可以更了解。

題外話,去爬 websocket 的資料時,想要複製別人的 code 下來 rework 時,常常缺東西缺西,

其中特別是關於環境的設定。

Docker 真的很方便,有了 Dockerfile 把大家的環境固定下來,功能保證一定可以正常運作。

超棒的!

☝ツ☝

This post is licensed under CC BY 4.0 by the author.

👈 ツ 👍