※ 先建立基本的express後端服務:
1.建立新資料夾:WebSocket
mkdir websocket
2.進入資料夾:WebSocket
cd websocket
3. 安裝 Experss 到專案中npm init -y //初始化專案,建立 package.json 檔
npm install express
4.在 package.json 中type預設使用 CommonJS 模式改為 module
"keywords": [],
"author": "",
"license": "ISC",
"type": "module",
"description": "",
"dependencies": {
"express": "^5.1.0"
}
5.修改腳本
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
6.建立index.js:寫入基本的伺服器程式碼。
import express from 'express';
import http from 'http';
const app = express();
const server = http.createServer(app);
// 提供靜態檔案服務
app.use(express.static('public'));
// 定義路由
app.get('/hello', (_, res) => {
res.send('Hello World');
res.end();
});
// 啟動伺服器
server.listen(8080, () => {
console.log('Server started on port 8080');
});
7.啟動express
npm run dev

8.建立靜態資料夾:public --> index.html
<!DOCTYPE html>
<html>
<head>
<title>WebSocket minimal demo</title>
</head>
<body>
<p>index.html</p>
</body>
</html>
※ 建立基本的websocket伺服器:
1.引用websocket相關套件
npm install ws
2.index.js中引入
import { WebSocketServer } from 'ws';
...
// 創建websocket伺服器
const wss = new WebSocketServer({ server });
程式碼解說:
const wss = new WebSocketServer({ server })優點:
- WebSocket 伺服器可以與 HTTP/HTTPS 共用同一個埠,節省系統資源。
- 允許同一個端口既處理 HTTP/HTTPS 請求,也能支持 WebSocket 通訊。
※ 建立Server規則:
用來作為 WebSocket 應用程式的基礎,並實現雙向即時通信,例如聊天應用程式或通知系統。
wss.on('connection', ws => {
//收到訊息後要做的事
ws.on('message', message => {
//發送一個log到後端的終端
console.log('Received:' + message.toString());
});
//對著連接發送訊息
ws.send('Hello');
})
程式碼解說:
1.wss.on('connection', ws => {...}):
- wss是 WebSocket 伺服器,這行程式表示每當有新的客戶端(Client)連接到伺服器時,將執行指定的回呼函式。
- 回呼函式的參數 代表單一連接的 WebSocket 實例(Instance),用於處理該特定連接的操作。
2.ws.on('message', message => {...});:
- 這行程式表示每當伺服器端收到從客戶端發來的訊息()時,執行指定的回呼函式。
- 回呼函式內的 將收到的二進制訊息轉換為字串。
- 使用 將訊息記錄到伺服器的終端機(Console)。
3.ws.send('Hello'):
- 對當前 WebSocket 連接的客戶端發送字串訊息 「Hello」。
- 每次連接時,伺服器會主動向客戶端發送此訊息。
※ 透過Postman測試連線:
- 開啟Postman → NEW建立新專案 → 選擇WebSocket

- 輸入端口:8080

- 連線成功WebSocket:

- 從前端發送訊息:Hi

- 後端收到前端發送的訊息:

※ 實現WebSocket的特性範例:雙向溝通
使用setInterval函數:固定某一段時間不斷發送一個訊息。
setInterval(() => {
//呼叫websocket
wss.clients.forEach(client => {
client.send('Hi');
})
}, 1000);
程式碼解說:
1.setInterval(() => {...}, 1000);:
- setInterval是用來定期執行某段程式碼的函式,也就是定時器。
- 這裡的箭頭函式會每隔 1000 毫秒(1 秒)執行一次,也就是每隔一秒就會執行一段程式。
2.wss.clients:
- wss是 WebSocket 伺服器的實例。
- wss.clients是目前所有已連線客戶端(WebSocket 連接)的集合。
3.wss.clients.forEach(client => {...}):
- 迭代當前所有連線的客戶端。
- 每個client 都代表一個連線的 WebSocket 實例。
4.client.send('Hello'):
- 使用 WebSocket 的 方法,向該特定客戶端發送字串訊息 'Hello'。
當後端關機時和前端所的連結就會被切斷,就會出現Disconnected訊號:

重新連結:

成功連結:

對話回覆:

※ 建立聊天室首要任務:區分用戶連線
建立群組聊天室:
ws.on('message', message => {
//轉發訊息給所有人
wss.clients.forEach(client => {
//後端伺服器留紀錄
console.log(ws.id + message.toString());
client.send(ws.id + message.toString());
});
});
程式碼解說:
1.ws.on('message', message => {...});:
- 這行程式表示每當伺服器端收到從客戶端發來的訊息()時,執行指定的回呼函式。
- 回呼函式內的 將收到的二進制訊息轉換為字串。
- 使用 將訊息記錄到伺服器的終端機(Console)。
2.wss.clients.forEach(client => {...}):
- wss.clients是目前所有已連線客戶端(WebSocket 連接)的集合。
- 迭代當前所有連線的客戶端。
- 每個client 都代表一個連線的 WebSocket 實例。
3.console.log(ws.id + message.toString()):
- 將接收到的訊息內容輸出到伺服器的終端機(Console),方便開發者或系統管理員檢查訊息記錄。
- 用ws.id 來告訴接收端這個訊息是來自哪個客戶端。
4.client.send(ws.id + message.toString()):
- 用ws.id 來告訴接收端這個訊息是來自哪個客戶端。
- 使得所有連線的用戶都能接收到來自任何其他使用者的訊息。
連線結果:

建立第二個連線用戶:

聊天室雛型:

將每個連線去做一個標示:
wss.on('connection', ws => {
//將每個連線去做一個標示:
ws.id = Math.round(Math.random() * 100);//產生0~100隨機數字
//對著連接發送訊息
ws.send('Hello, your id is' + ws.id);
...})
程式碼解說:
1.為新連線分配一個唯一標示:
ws.id = Math.round(Math.random() * 100);
- ws.id:當前連線的 WebSocket 客戶端設置一個標示,用於識別該連線。
- Math.random() * 100:將隨機小數放大為0 至100 之間的隨機浮點數。
- Math.round():將浮點數四捨五入為整數,得到範圍在0 至 100 之間的隨機數字。
2.向客戶端發送訊息:
ws.send('Hello, your id is ' + ws.id);
- 客戶端可以通過接收此訊息獲得自己的唯一 id。
3.連線成功客戶端的id:

群組聊天室基本架構結果:

建立密語功能:只對某人傳訊息
if (msg.split(' ')[0] === '/m') {
const parts = msg.split(' ');
// 確保命令格式正確
if (parts.length < 3) {
console.error('格式錯誤:請使用 "/m <target> <message>"');
ws.send('格式錯誤:請使用 "/m <target> <message>"');
return;
}
const target = parseInt(parts[1], 10);
// 檢查目標是否為有效數字
if (isNaN(target)) {
console.error(`錯誤:目標 ID 必須是數字,接收到:${parts[1]}`);
ws.send(`錯誤:目標 ID 必須是數字,接收到:${parts[1]}`);
return;
}
const message = parts[2]; // 只取第三部分當訊息
let clientFound = false;
wss.clients.forEach(client => {
if (client.id === target) {
clientFound = true;
console.log(`[m] ${ws.id} says ${message}`);
client.send(`[m] ${ws.id} says ${message}`);
}
});
if (!clientFound) {
console.error(`未找到目標客戶端 ID:${target}`);
ws.send(`未找到目標客戶端 ID:${target}`);
}
return;
}
程式碼解說:
1.檢查指令是否是 /m:
if (msg.split(' ')[0] === '/m') {}
- 接收到的msg 是否以/m 開頭,如果不是 ,程式會跳過此邏輯。
2.分割命令內容:
const parts = msg.split(' ');
使用split 分割字符串,將空格作為分隔符。分割後, parts是一個數組:
- parts[0]是指令本身 。
- parts[1]是目標 ID 。
- parts[2]是要發送的訊息 。
3.檢查命令格式是否正確:
if (parts.length < 3) {
console.error('格式錯誤:請使用 "/m <target> <message>"');
ws.send('格式錯誤:請使用 "/m <target> <message>"');
return;
}
- 如果分割後的數組長度不足 3,表示命令格式錯誤(例如缺少目標 ID 或訊息),程式會提示並結束執行。

4.提取目標 ID 並轉換為數字:
const target = parseInt(parts[1], 10);
if (isNaN(target)) {
console.error(`錯誤:目標 ID 必須是數字,接收到:${parts[1]}`);
ws.send(`錯誤:目標 ID 必須是數字,接收到:${parts[1]}`);
return;
}
- 使用parseInt 將目標 ID 轉換為數字。如果轉換失敗(NaN),程式會報錯並結束執行。
- parseInt用來將字符串(string)轉換為整數(integer)。它經常被用於需要從字符串中提取數字的場合。

5.提取訊息內容:
const message = parts[2];
- 從分割數組中提取訊息內容,這是用戶希望發送的消息。
6.搜尋目標客戶端並發送消息:
let clientFound = false;
wss.clients.forEach(client => {
if (client.id === target) {
clientFound = true;
console.log(`[m] ${ws.id} says ${message}`);
client.send(`[m] ${ws.id} says ${message}`);
}
});
- 這段程式碼會遍歷所有的 WebSocket 客戶端(wss.clients),找到 ID 與目標匹配的客戶端並發送消息。
- 如果找到匹配的客戶端,會將消息發送給該客戶端。
- 並且會將操作結果記錄在伺服器日誌中。
7.處理找不到目標客戶端的情況:
if (!clientFound) {
console.error(`未找到目標客戶端 ID:${target}`);
ws.send(`未找到目標客戶端 ID:${target}`);
}
- 如果在遍歷中未找到目標客戶端,程式會報錯並通知發送消息的用戶。
8.結束執行:使用return 結束執行,避免繼續後續邏輯。
結果:
