3. 教你用WebSocket构建一个实时聊天应用
系列目录
1.探索WebSocket:实时网络的心跳!
2.WebSocket进阶: 深入探究实时通信的最佳实践与优化技巧
1. 了解聊天室的基本需求
在聊天室中,我们通常需要实现以下功能:
● 用户连接和断开时的通知。
● 用户发送和接收消息的实时更新。
● 管理多用户的消息同步。
● 可扩展的架构以便未来添加更多功能,比如私聊、消息存储等。
2. WebSocket基础: 建立连接
WebSocket提供了一个轻松的API,能够在浏览器和服务器之间建立持久连接。每当用户打开聊天室时,客户端与服务器之间进行WebSocket连接,之后,客户端和服务器之间的通信就不需要重复建立HTTP请求。
基本的WebSocket连接步骤如下:
- 客户端发送连接请求
- 服务器响应并确认连接
- 建立WebSocket连接后,双方可以实时发送和接收消息。
3. 项目架构及代码实现
后端源码: 使用Node.js 搭建 WebSocket服务器
我们可以使用Node.js的ws 库来搭建WebSocket服务器,监听每一个连接的客户端,转发消息到所有用户,从而实现实时消息的广播。
首先,安装ws库:
npm install ws
创建一个服务器文件server.js:
// server.js
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
const clients = new Set();
wss.on('connection',(ws) = >{
console.log("A new user connected")
client.add(ws);
ws.on('message',(message) => {
console.log(`Receieve message: ${message}`);
// 广播信息到所有连接的客户端
clients.forEach(client = >{
if (client.readyState == WebSocket.OPEN){
client.send(message)
}
});
});
ws.on('close',() = >{
console.log("A user disconnected.")
client.delete(ws);
});
});
console.log("WebSocket server is running on ws://localhost:8080")
在这个例子中,我们创建了一个WebSocket服务器,监听端口8080。当一个新客户端连接时,服务器会将该客户端添加到clients集合中,所有接收到的消息会被广播到每一个已连接的客户端。
前端代码:简单的聊天室页面
创建一个index.html文件,包含基本的页面结构和WebSocket连接的JavaScript代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebSocket Chat Room</title>
</head>
<body>
<h1>Welcome to the Chat Room!</h1>
<div id="chat">
<div id="messages"></div>
<input type="text" id="messageInput" placeholder="Type your message..." />
<button onclick="sendMessage()">Send</button>
</div>
<script>
const ws = new WebSocket('ws://localhost:8080');
ws.open = () =>{
console.log('Connected to the chat server !');
};
ws.onmessage = (message) =>{
const messageDiv= document.getElementById('message');
const newMessage = document.createElement('div');
newMessage.textContent = event.data;
messageDiv.appendChild(newMessage);
};
ws.onclose = () = {
console.log('Disconnected from the chat sever.');
};
function sendMessage (){
const input = document.getElementById('messageInput');
if(input.value){
ws.send(input.value);
input.value='';
}
}
</script>
</body>
</html>
在这个页面中,我们使用了一个WebSocket连接服务器,并将用户发送的消息广播到所有连接的客户端上。通过监听onmessage事件,页面可以实时更新,显示其他用户发来的新消息。
⚠️注意:WebSocket的文本消息传递的时候默认格式是Binary,我们收到消息之后需要进行解析。
const data = event.data;
if (data instanceof Blob) {
const reader = new FileReader();
// 异步接收readAsText() 解析后的结果
reader.onload = function() {
console.log("Received message:", reader.result); // 输出转换后的字符串
};
reader.readAsText(data); // 读取 Blob 数据为文本
console.log("Message type:", data);
} else {
console.log("JSON FORMAT");
}
4. 实现多用户消息格式:带用户名的消息
为了区分不同用户的消息,我们可以在客户端发送消息时附加用户名信息。让用户输入自己的昵称,并在发送消息时附带昵称。
修改前端代码,添加用户名输入:
<input type="text" id="username" placeholder="Enter your name..." />
<button onclick="joinChat()">Join Chat</button>
修改sendMessage函数,使其包含用户名:
function joinChat() {
const usernameInput = document.getElementById('username');
if (usernameInput.value) {
ws.send(JSON.stringify({ type: 'join', username: usernameInput.value }));
}
}
function sendMessage() {
const input = document.getElementById('messageInput');
const username = document.getElementById('username').value;
if (input.value && username) {
ws.send(JSON.stringify({ type: 'message', username, content: input.value }));
input.value = '';
}
}
修改服务器代码来解析消息格式:
ws.on('message', (data) => {
const messageData = JSON.parse(data);
let broadcastMessage = "";
if (messageData.type === 'join') {
broadcastMessage = `${messageData.username} joined the chat!`;
} else if (messageData.type === 'message') {
broadcastMessage = `${messageData.username}: ${messageData.content}`;
}
// 广播给所有客户端
clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(broadcastMessage);
}
});
});
在这种方式下,每个用户的消息都将包含用户名,便于区分不同用户的聊天内容。
5. 提升聊天室的用户体验
为了让聊天室的体验更好,可以尝试增加以下功能:
(1) 显示用户的加入/退出通知
每当一个用户连接或断开时,服务器都可以发送通知信息,广播给所有其他在线用户。
(2) 滚动消息视图
在消息框中让新消息自动滚动到最底部,提供更好的聊天体验。可以在每次新消息到来时自动滚动#messages元素:
ws.onmessage = (event) => {
const messagesDiv = document.getElementById('messages');
const newMessage = document.createElement('div');
newMessage.textContent = event.data;
messagesDiv.appendChild(newMessage);
messagesDiv.scrollTop = messagesDiv.scrollHeight; // 滚动到底部
};
(3) 断线重连
在网络波动或服务器重新启动时,自动重新连接WebSocket,使聊天室更加稳定:
ws.onclose = () => {
console.log('Disconnected from the server. Reconnecting...');
setTimeout(() => {
// 重新连接
connectWebSocket();
}, 1000);
};
``