node.js + html + Sealos容器云 搭建简易多人实时聊天室demo 带源码

node.js + html + Sealos容器云 搭建简易多人实时聊天室demo 带源码

前言

hello哦盆友们,这次我们来十几行代码做一个超简单的多人聊天室,涉及功能不多,只是让大家熟悉娱乐一下,这次我们一切从简 使用到的技术为 node.js + html + sealos 云储存 * (sealos官方没给我打钱有官网人员看到了记得给打点。)

功能介绍(demo演示)

这是本地启动的服务,实现多人实时聊天的demo

多人实时聊天

sealos官网配置

sealos 云储存

由于我们聊天需要储存聊天记录等数据,所以这次使用了sealos云里面的 mongoDB 来储存我们的聊天数据, sealos云注册免费赠送我们额度,足够我们使用了,下面介绍一下sealos如何使用。

✨ 首先进入 sealos 云 官网 没有账户的注册一个账户,完成后登录我们点击极速体验按钮进入到工作台

✨ 进入到工作台后我们在下面找到数据库 如下图

✨ 进入到工作台后我们右上角选择新建 然后选择mongoDB 直接

✨ 这样我们就创建好了一个云的mogoDB储存啦 途中方框圈中的地方呆会儿我们在node服务里面要使用

node.js 编写服务端代码

✨ 首先我们在一个文件夹内初始化一个package.json 文件,我们这次使用到了 express框架 + socket.io + cors + mongoose 大家安装这几个依赖就可以了 复制到同学别忘了 npm install 一下哦

bash 复制代码
{
  "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 功能作用我都给注释到代码层面了可自行研究

bash 复制代码
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 + 调用接口

bash 复制代码
<!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> 

整体项目目录

部署到服务器

这里大家自行部署到服务器就行,给你的好友展示一下。如果有需要部署教程的 等有时间出个部署教程

相关推荐
scimence11 分钟前
html 列动态布局
前端·css·html·列动态布局
秋淮安14 分钟前
Web前端开发--HTML
前端
黑客老李24 分钟前
一次使用十六进制溢出绕过 WAF实现XSS的经历
java·运维·服务器·前端·sql·学习·xss
幸运小圣30 分钟前
LeetCode热题100- 轮转数组【JavaScript讲解】
javascript·算法·leetcode
Elcker34 分钟前
Tauri教程-实战篇-第六节 托盘、请求完善
javascript·rust
野槐3 小时前
react实例与总结(一)
javascript·react native·react.js
IT专家-大狗3 小时前
如何在Node.js中使用中间件处理请求
中间件·node.js
phper83 小时前
Node.js调用DeepSeek Api 实现本地智能聊天的简单应用
node.js
小涵3 小时前
Python和JavaScript在字符串比较上的差异
开发语言·javascript·python
Goodbaibaibai3 小时前
vue基础(五)
前端·javascript·vue.js