前言
hello哦盆友们,这次我们来十几行代码做一个超简单的多人聊天室,涉及功能不多,只是让大家熟悉娱乐一下,这次我们一切从简 使用到的技术为 html" title=node.js>node.js + html + sealos 云储存 * (sealos官方没给我打钱有官网人员看到了记得给打点。)
功能介绍(demo演示)
这是本地启动的服务,实现多人实时聊天的demo
多人实时聊天
sealos官网配置
sealos 云储存
由于我们聊天需要储存聊天记录等数据,所以这次使用了sealos云里面的 mongoDB 来储存我们的聊天数据, sealos云注册免费赠送我们额度,足够我们使用了,下面介绍一下sealos如何使用。
✨ 首先进入 sealos 云 官网 没有账户的注册一个账户,完成后登录我们点击极速体验按钮进入到工作台
✨ 进入到工作台后我们在下面找到数据库 如下图
✨ 进入到工作台后我们右上角选择新建 然后选择mongoDB 直接
✨ 这样我们就创建好了一个云的mogoDB储存啦 途中方框圈中的地方呆会儿我们在node服务里面要使用
html" title=node.js>node.js 编写服务端代码
✨ 首先我们在一个文件夹内初始化一个package.json 文件,我们这次使用到了 express框架 + socket.io + cors + mongoose 大家安装这几个依赖就可以了 复制到同学别忘了 npm install 一下哦
{
"name": "chat-server",
"version": "1.0.0",
"description": "实时聊天服务器",
"main": "server.js",
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js"
},
"dependencies": {
"express": "^4.17.1",
"socket.io": "^4.4.1",
"cors": "^2.8.5",
"mongoose": "^6.8.0"
},
"devDependencies": {
"nodemon": "^2.0.15"
}
}
✨ 下面我们创建一个 server.js 功能作用我都给注释到代码层面了可自行研究
const express = require('express');
const app = express();
const http = require('http').createServer(app);
const io = require('socket.io')(http, {
cors: {
origin: '*', // 允许所有来源访问
methods: ['GET', 'POST'],
allowedHeaders: ['Content-Type'],
credentials: true
}
});
const cors = require('cors');
const mongoose = require('mongoose');
const connectWithRetry = async () => {
try {
await mongoose.connect('这里替换成你的', {
useNewUrlParser: true,
useUnifiedTopology: true,
serverSelectionTimeoutMS: 5000,
socketTimeoutMS: 45000,
});
console.log('MongoDB 连接成功');
} catch (err) {
console.error('MongoDB 连接失败,5秒后重试:', err);
setTimeout(connectWithRetry, 5000);
}
};
connectWithRetry();
// 添加 MongoDB 连接错误处理
mongoose.connection.on('error', err => {
console.error('MongoDB 连接错误:', err);
});
mongoose.connection.on('disconnected', () => {
console.log('MongoDB 连接断开');
});
// 定义消息模型
const messageSchema = new mongoose.Schema({
userId: String,
username: String,
content: String,
timestamp: { type: Date, default: Date.now }
});
const Message = mongoose.model('Message', messageSchema);
// 启用 CORS
app.use(cors({
origin: '*', // 允许所有来源访问,生产环境建议设置具体的域名
methods: ['GET', 'POST'],
allowedHeaders: ['Content-Type'],
credentials: true
}));
app.use(express.json());
// 存储在线用户
let onlineUsers = new Map();
// Socket.IO 连接处理
io.on('connection', (socket) => {
console.log('用户已连接');
// 获取历史消息
socket.on('getHistory', async () => {
try {
const messages = await Message.find()
.sort({ timestamp: -1 })
.limit(50); // 限制返回最近50条消息
socket.emit('history', messages.reverse());
} catch (err) {
console.error('获取历史消息失败:', err);
}
});
// 用户加入聊天
socket.on('join', (userData) => {
onlineUsers.set(socket.id, userData.username);
io.emit('userList', Array.from(onlineUsers.values()));
});
// 处理消息发送
socket.on('sendMessage', async (message) => {
const messageData = {
userId: socket.id,
username: onlineUsers.get(socket.id),
content: message,
timestamp: new Date()
};
try {
// 保存消息到数据库
const newMessage = new Message(messageData);
await newMessage.save();
// 广播消息给所有客户端
io.emit('message', messageData);
} catch (err) {
console.error('保存消息失败:', err);
socket.emit('error', '消息发送失败');
}
});
// 处理断开连接
socket.on('disconnect', () => {
onlineUsers.delete(socket.id);
io.emit('userList', Array.from(onlineUsers.values()));
console.log('用户已断开连接');
});
});
// 添加获取历史消息的 REST API
app.get('/api/messages', async (req, res) => {
try {
const page = parseInt(req.query.page) || 1;
const limit = parseInt(req.query.limit) || 50;
const messages = await Message.find()
.sort({ timestamp: -1 })
.skip((page - 1) * limit)
.limit(limit);
const total = await Message.countDocuments();
res.json({
messages: messages.reverse(),
pagination: {
current: page,
limit,
total
}
});
} catch (err) {
res.status(500).json({ error: '获取消息失败' });
}
});
// 基础路由
app.get('/', (req, res) => {
res.send('聊天服务器正在运行');
});
// 启动服务器
const PORT = process.env.PORT || 3000;
http.listen(PORT, () => {
console.log(`服务器运行在端口 ${PORT}`);
});
前端ui + 调用接口
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>实时聊天室</title>
<style>
.chat-container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.messages {
height: 400px;
border: 1px solid #ccc;
overflow-y: auto;
padding: 10px;
margin-bottom: 20px;
}
.message {
margin-bottom: 10px;
padding: 5px;
}
.message .username {
font-weight: bold;
color: #2196F3;
}
.message .time {
color: #999;
font-size: 0.8em;
}
.input-area {
display: flex;
gap: 10px;
}
#messageInput {
flex: 1;
padding: 8px;
}
.user-list {
border: 1px solid #ccc;
padding: 10px;
margin-bottom: 20px;
}
</style>
</head>
<body>
<div class="chat-container">
<h2>实时聊天室</h2>
<div class="user-list">
<h3>在线用户</h3>
<ul id="userList"></ul>
</div>
<div class="messages" id="messages"></div>
<div class="input-area">
<input type="text" id="messageInput" placeholder="输入消息...">
<button onclick="sendMessage()">发送</button>
</div>
</div>
<script src="https://cdn.socket.io/4.4.1/socket.io.min.js"></script>
<script>
// 连接 Socket.IO 服务器
const socket = io('http://localhost:3000');
// 获取DOM元素
const messagesDiv = document.getElementById('messages');
const messageInput = document.getElementById('messageInput');
const userList = document.getElementById('userList');
// 生成随机用户名
const username = '用户' + Math.floor(Math.random() * 1000);
// 加入聊天
socket.emit('join', { username });
// 获取历史消息
socket.emit('getHistory');
// 监听历史消息
socket.on('history', (messages) => {
messages.forEach(message => {
appendMessage(message);
});
scrollToBottom();
});
// 监听新消息
socket.on('message', (message) => {
console.log(message,"message");
appendMessage(message);
scrollToBottom();
});
// 监听用户列表更新
socket.on('userList', (users) => {
userList.innerHTML = users
.map(user => `<li>${user}</li>`)
.join('');
});
// 发送消息
function sendMessage() {
const message = messageInput.value.trim();
if (message) {
socket.emit('sendMessage', message);
messageInput.value = '';
}
}
// 添加消息到界面
function appendMessage(message) {
const messageDiv = document.createElement('div');
messageDiv.className = 'message';
const time = new Date(message.timestamp).toLocaleTimeString();
messageDiv.innerHTML = `
<span class="username">${message.username}</span>
<span class="time">${time}</span>
<div class="content">${message.content}</div>
`;
messagesDiv.appendChild(messageDiv);
}
// 滚动到底部
function scrollToBottom() {
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
// 按回车发送消息
messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendMessage();
}
});
// 加载更多历史消息
let currentPage = 1;
async function loadMoreMessages() {
try {
const response = await fetch(`http://localhost:3000/api/messages?page=${currentPage}&limit=20`);
const data = await response.json();
data.messages.forEach(message => {
const messageDiv = document.createElement('div');
messageDiv.className = 'message';
// ... 处理消息显示
});
currentPage++;
} catch (error) {
console.error('加载消息失败:', error);
}
}
</script>
</body>
</html>
整体项目目录
部署到服务器
这里大家自行部署到服务器就行,给你的好友展示一下。如果有需要部署教程的 等有时间出个部署教程