在实时应用的开发中,WebSocket 已经成为实现高效、低延迟实时通讯的关键技术。通过建立持久的双向连接,WebSocket 不仅可以减少网络请求的开销,还能支持高效的数据传输。在本教程中,我们将创建一个更复杂的聊天应用,除了实现基本的 WebSocket 连接外,还将扩展一些常见的应用场景:私聊、群聊、消息持久化、用户身份验证等。
我们将使用 Node.js 和 ws 库创建 WebSocket 服务器,并通过 Redis 实现群聊的消息广播。
ws
和 redis
库首先,创建 Node.js 项目并安装所需的依赖:
npm init -y
npm install ws redis
在 server.js
中,我们将实现一个 WebSocket 服务器,支持群聊和私聊功能。
// server.js
const WebSocket = require('ws');
const redis = require('redis');
// 创建 WebSocket 服务器,监听端口 8080
const wss = new WebSocket.Server({ port: 8080 });
// 连接 Redis 客户端
const client = redis.createClient();
// 存储所有连接的 WebSocket 客户端
let users = {};
wss.on('connection', ws => {
console.log('客户端已连接');
// 处理消息接收
ws.on('message', (message) => {
const data = JSON.parse(message);
const { type, user, content, target } = data;
if (type === 'chat') {
// 广播消息到所有客户端(群聊)
broadcast(user, content);
} else if (type === 'private') {
// 私聊消息(发送到指定目标)
privateMessage(user, target, content);
} else if (type === 'history') {
// 请求聊天记录
getHistory(ws);
}
});
// 连接成功时,给客户端一个欢迎消息
ws.on('open', () => {
ws.send(JSON.stringify({ user: 'server', content: '欢迎来到聊天室!' }));
});
// 监听客户端断开连接
ws.on('close', () => {
console.log('客户端已断开连接');
// 用户断开连接后,清理用户信息
Object.keys(users).forEach((key) => {
if (users[key] === ws) {
delete users[key];
}
});
});
// 广播消息到所有客户端
function broadcast(user, content) {
wss.clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify({ user, content }));
}
});
// 将聊天记录保存到 Redis 中
client.rpush('chatHistory', JSON.stringify({ user, content }));
}
// 私聊功能:发送消息给特定的用户
function privateMessage(user, target, content) {
const targetSocket = users[target];
if (targetSocket) {
targetSocket.send(JSON.stringify({ user, content }));
} else {
ws.send(JSON.stringify({ user: 'server', content: '用户不在线' }));
}
}
// 获取历史聊天记录
function getHistory(ws) {
client.lrange('chatHistory', 0, -1, (err, messages) => {
if (err) {
ws.send(JSON.stringify({ user: 'server', content: '获取聊天记录失败' }));
} else {
ws.send(JSON.stringify({ user: 'server', content: messages }));
}
});
}
// 注册用户
ws.on('message', (data) => {
const message = JSON.parse(data);
if (message.type === 'register') {
users[message.user] = ws;
console.log(`${message.user} 已注册`);
}
});
});
为了实现用户身份验证,我们可以通过 WebSocket 连接时传递一个 token,来验证用户的身份。
// 用户身份验证
ws.on('connection', (socket, request) => {
const token = request.url.split('token=')[1]; // 从 URL 中获取 token
if (isValidToken(token)) {
// 如果 token 验证通过,继续连接
socket.send('身份验证通过');
} else {
socket.close(); // 否则关闭连接
}
});
我们将使用 Vue 3 创建聊天应用,并实现消息发送、接收、私聊等功能。
通过 Vue CLI 创建一个新的 Vue 项目:
vue create websocket-chat
在 ChatRoom.vue
中实现 WebSocket 客户端:
<template>
<div class="chat-room">
<div class="messages">
<div v-for="(message, index) in messages" :key="index" class="message">
<strong>{{ message.user }}:</strong> {{ message.content }}
</div>
</div>
<input v-model="newMessage" @keyup.enter="sendMessage" placeholder="Type a message..." />
<button @click="sendPrivateMessage">私聊</button>
</div>
</template>
<script>
export default {
data() {
return {
socket: null,
messages: [],
newMessage: '',
user: 'User' + Math.floor(Math.random() * 1000),
targetUser: '', // 私聊目标用户
};
},
mounted() {
this.socket = new WebSocket('ws://localhost:8080');
this.socket.onopen = () => {
this.socket.send(JSON.stringify({ type: 'register', user: this.user }));
};
this.socket.onmessage = (event) => {
const message = JSON.parse(event.data);
this.messages.push(message);
this.scrollToBottom();
};
},
methods: {
sendMessage() {
if (this.newMessage.trim()) {
this.socket.send(JSON.stringify({ type: 'chat', user: this.user, content: this.newMessage }));
this.newMessage = '';
}
},
sendPrivateMessage() {
if (this.targetUser && this.newMessage.trim()) {
this.socket.send(
JSON.stringify({
type: 'private',
user: this.user,
target: this.targetUser,
content: this.newMessage,
})
);
this.newMessage = '';
}
},
scrollToBottom() {
const container = this.$refs.messageContainer;
container.scrollTop = container.scrollHeight;
},
},
};
</script>
为了保障通信安全,可以使用 AES 加密协议加密传输的消息内容,确保数据在传输过程中不会被窃取。
当 WebSocket 服务器需要处理大量连接时,可以使用连接池和负载均衡技术。例如,使用 Nginx 配置 WebSocket 反向代理。
到这里,这篇文章就和大家说再见啦!我的主页里还藏着很多 篇 前端 实战干货,感兴趣的话可以点击头像看看,说不定能找到你需要的解决方案~
创作这篇内容花了很多的功夫。如果它帮你解决了问题,或者带来了启发,欢迎:
点个赞❤️ 让更多人看到优质内容
关注「前端极客探险家」 每周解锁新技巧
收藏文章⭐️ 方便随时查阅
特别提醒:
转载请注明原文链接,商业合作请私信联系
感谢你的阅读!我们下篇文章再见~