Node.js實現(xiàn)WebSocket的詳細教程
Node.js實現(xiàn)WebSocket教程
1. WebSocket簡介
WebSocket是一種在單個TCP連接上提供全雙工通信的協(xié)議,允許服務(wù)器和客戶端之間進行實時、雙向通信。本教程將詳細講解如何在Node.js中實現(xiàn)WebSocket。
2. 技術(shù)選型
我們將使用ws庫來實現(xiàn)WebSocket服務(wù)器,并結(jié)合express創(chuàng)建Web應(yīng)用。
2.1 安裝依賴
# 創(chuàng)建項目目錄 mkdir nodejs-websocket-demo cd nodejs-websocket-demo # 初始化項目 npm init -y # 安裝依賴 npm install express ws uuid
依賴說明:
express: Web應(yīng)用框架ws: WebSocket服務(wù)器實現(xiàn)uuid: 生成唯一標識符
3. 項目結(jié)構(gòu)
nodejs-websocket-demo/ │ ├── public/ │ ├── index.html │ └── client.js ├── server.js └── package.json
4. 詳細實現(xiàn)
4.1 WebSocket服務(wù)器 (server.js)
const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const { v4: uuidv4 } = require('uuid');
const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });
// 存儲客戶端連接
const clients = new Map();
// 靜態(tài)文件服務(wù)
app.use(express.static('public'));
// WebSocket連接處理
wss.on('connection', (ws) => {
// 為每個客戶端分配唯一ID
const clientId = uuidv4();
// 存儲客戶端連接
clients.set(clientId, ws);
// 發(fā)送客戶端ID
ws.send(JSON.stringify({
type: 'connection',
clientId: clientId
}));
// 廣播新用戶連接
broadcast({
type: 'userJoined',
clientId: clientId,
message: `用戶 ${clientId} 已加入聊天`
}, clientId);
// 消息處理
ws.on('message', (message) => {
try {
const parsedMessage = JSON.parse(message);
switch(parsedMessage.type) {
case 'chat':
handleChatMessage(clientId, parsedMessage);
break;
case 'typing':
handleTypingNotification(clientId, parsedMessage);
break;
default:
console.log('未知消息類型:', parsedMessage.type);
}
} catch (error) {
console.error('消息解析錯誤:', error);
}
});
// 連接關(guān)閉處理
ws.on('close', () => {
// 移除客戶端
clients.delete(clientId);
// 廣播用戶離開
broadcast({
type: 'userLeft',
clientId: clientId,
message: `用戶 ${clientId} 已離開聊天`
}, clientId);
});
});
// 聊天消息處理
function handleChatMessage(senderId, message) {
broadcast({
type: 'chat',
clientId: senderId,
message: message.message
}, senderId);
}
// 輸入狀態(tài)通知
function handleTypingNotification(senderId, message) {
broadcast({
type: 'typing',
clientId: senderId,
isTyping: message.isTyping
}, senderId);
}
// 廣播消息
function broadcast(message, excludeClientId = null) {
clients.forEach((client, clientId) => {
if (client.readyState === WebSocket.OPEN && clientId !== excludeClientId) {
client.send(JSON.stringify(message));
}
});
}
// 服務(wù)器啟動
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(`WebSocket服務(wù)器運行在 ${PORT} 端口`);
});4.2 客戶端HTML (public/index.html)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>WebSocket聊天室</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
#chat-messages {
height: 300px;
overflow-y: scroll;
border: 1px solid #ccc;
padding: 10px;
margin-bottom: 10px;
}
</style>
</head>
<body>
<div id="chat-messages"></div>
<input type="text" id="message-input" placeholder="輸入消息">
<button id="send-btn">發(fā)送</button>
<script src="client.js"></script>
</body>
</html>4.3 客戶端JavaScript (public/client.js)
const socket = new WebSocket('ws://localhost:3000');
let clientId = null;
const chatMessages = document.getElementById('chat-messages');
const messageInput = document.getElementById('message-input');
const sendBtn = document.getElementById('send-btn');
// WebSocket事件處理
socket.addEventListener('open', (event) => {
appendMessage('系統(tǒng)', '連接成功');
});
socket.addEventListener('message', (event) => {
const message = JSON.parse(event.data);
switch(message.type) {
case 'connection':
clientId = message.clientId;
appendMessage('系統(tǒng)', `您的ID是: ${clientId}`);
break;
case 'chat':
appendMessage(message.clientId, message.message);
break;
case 'userJoined':
case 'userLeft':
appendMessage('系統(tǒng)', message.message);
break;
case 'typing':
handleTypingNotification(message);
break;
}
});
socket.addEventListener('close', (event) => {
appendMessage('系統(tǒng)', '連接已關(guān)閉');
});
// 發(fā)送消息
sendBtn.addEventListener('click', sendMessage);
messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendMessage();
}
});
function sendMessage() {
const message = messageInput.value.trim();
if (message) {
socket.send(JSON.stringify({
type: 'chat',
message: message
}));
appendMessage(clientId, message);
messageInput.value = '';
}
}
// 消息追加到聊天窗口
function appendMessage(sender, text) {
const messageEl = document.createElement('div');
messageEl.innerHTML = `<strong>${sender}:</strong> ${text}`;
chatMessages.appendChild(messageEl);
chatMessages.scrollTop = chatMessages.scrollHeight;
}
// 處理打字狀態(tài)通知
function handleTypingNotification(message) {
// 可以在這里實現(xiàn)打字狀態(tài)提示
}5. 運行項目
# 啟動服務(wù)器 node server.js # 訪問 http://localhost:3000
6. 功能特點
- 實時雙向通信
- 唯一客戶端標識
- 廣播消息機制
- 連接/斷開事件處理
- 聊天消息和系統(tǒng)通知
7. 性能與擴展建議
- 生產(chǎn)環(huán)境考慮使用Redis等外部存儲管理WebSocket連接
- 增加身份驗證機制
- 實現(xiàn)消息持久化
- 使用負載均衡
8. 安全注意事項
- 使用WSS(WebSocket Secure)
- 實現(xiàn)連接速率限制
- 驗證和過濾消息內(nèi)容
- 防止跨站W(wǎng)ebSocket劫持
到此這篇關(guān)于Node.js實現(xiàn)WebSocket的詳細教程的文章就介紹到這了,更多相關(guān)node.js websocket實現(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
教你在heroku云平臺上部署Node.js應(yīng)用
heroku是構(gòu)建在AWS之上的一個PaaS云平臺,現(xiàn)在支持Ruby, Node.js, Python, Java, 和 PHP,代碼的部署是通過git進行,編譯和運行都是自動的。2014-07-07
nodejs的http和https下載遠程資源post數(shù)據(jù)實例
這篇文章主要為大家介紹了nodejs的http和https下載遠程資源post數(shù)據(jù)實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-09-09
express框架+bootstrap美化ejs模板實例分析
這篇文章主要介紹了express框架+bootstrap美化ejs模板,結(jié)合實例形式分析了express框架引入bootstrap結(jié)合ejs模版引擎相關(guān)操作技巧與注意事項,需要的朋友可以參考下2023-05-05
Windows下快速搭建NodeJS本地服務(wù)器的步驟
本篇文章主要介紹了Windows下快速搭建NodeJS本地服務(wù)器的步驟,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-08-08
node.js解決客戶端請求數(shù)據(jù)里面中文亂碼的事件方法
本文主要介紹了node.js解決客戶端請求數(shù)據(jù)里面中文亂碼的事件方法,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-12-12
Node+Express搭建HTTPS服務(wù)的實現(xiàn)
最近開發(fā)需要搭建一個https的服務(wù),正好最近在用nodejs和express,本文章主要介紹了Node+Express搭建HTTPS服務(wù)的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下2023-12-12
Node.js 實現(xiàn) Stripe 支付的實現(xiàn)方法
本文介紹了使用Stripe支付系統(tǒng)的實現(xiàn)方法,本文結(jié)合實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2025-11-11

