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

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

  • 前言
    • 功能介绍(demo演示)
    • sealos官网配置
    • node.js 编写服务端代码
    • 前端ui + 调用接口
    • 整体项目目录
    • 部署到服务器

前言

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 一下哦

{
  "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> 

整体项目目录

在这里插入图片描述

部署到服务器

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/966764.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MYSQL索引与视图

一、新建数据库 mysql> create database mydb15_indexstu; mysql> use mydb15_indexstu; 二、新建表 &#xff08;1&#xff09;学生表Student mysql> create table Student(-> Sno int primary key auto_increment,-> Sname varchar(30) not null unique,-…

win10向windows server服务器传输文件

win10向windows server服务器传输文件 遇到无法直接拖动文件进行传输时 解决方案&#xff1a; 1.点击显示选项 2.点击本地资源-详细信息 3.在窗口中选择你需要共享的磁盘 4.然后远程连接到Windows server服务器 5.登录Windows server服务器后&#xff0c;在此电脑下就能看…

【教程】docker升级镜像

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 自动升级 手动升级 无论哪种方式&#xff0c;最重要的是一定要通过-v参数做数据的持久化&#xff01; 自动升级 使用watchtower&#xff0c;可…

HTML应用指南:利用GET请求获取全国盒马门店位置信息

随着新零售业态的发展,门店位置信息的获取变得至关重要。作为新零售领域的先锋,盒马鲜生不仅在商业模式创新上持续领先,还积极构建广泛的门店网络,以支持其不断增长的用户群体。本篇文章,我们将继续探究GET请求的实际应用,我们使用Python的requests库通过GET请求,从盒马…

Linux内核数据结构之链表

对于链表的优缺点,我们对比数组可以说出一些,但在随机存储的情况下,我们会选择链表来处理,而我们使用双向链表时,经常会定义成如下形式: struct list_node {TYPE data;struct list_node *prev,*next; }; 相对应的链表结构如下: 对于该数据结构定义,存在一个局限,整个…

ctf网络安全题库 ctf网络安全大赛答案

此题解仅为部分题解&#xff0c;包括&#xff1a; 【RE】&#xff1a;①Reverse_Checkin ②SimplePE ③EzGame 【Web】①f12 ②ezrunner 【Crypto】①MD5 ②password ③看我回旋踢 ④摩丝 【Misc】①爆爆爆爆 ②凯撒大帝的三个秘密 ③你才是职业选手 一、 Re ① Reverse Chec…

250207-MacOS修改Ollama模型下载及运行的路径

在 macOS 上&#xff0c;Ollama 默认将模型存储在 ~/.ollama/models 目录。如果您希望更改模型的存储路径&#xff0c;可以通过设置环境变量 OLLAMA_MODELS 来实现。具体步骤如下&#xff1a; 选择新的模型存储目录&#xff1a;首先&#xff0c;确定您希望存储模型的目标目录路…

C# OpenCvSharp 部署MOWA:多合一图像扭曲模型

目录 说明 效果 项目 代码 下载 参考 C# OpenCvSharp 部署MOWA&#xff1a;多合一图像扭曲模型 说明 算法模型的paper名称是《MOWA: Multiple-in-One Image Warping Model》 ariv链接 https://arxiv.org/pdf/2404.10716 效果 Stitched Image 翻译成中文意思是&…

CPP集群聊天服务器开发实践(一):用户注册与登录

目录 1 客户端用户注册与登录 1.1 主要思想 1.2 网络层 1.3 业务层 1.4 数据层 1.5 测试结果 1 客户端用户注册与登录 1.1 主要思想 实现网络层、业务层、数据层的解耦&#xff0c;提高系统的可维护性。 网络层&#xff1a;主要实现对客户端连接、客户端读写请求的捕获…

ARM嵌入式学习--第十四天(SPI)

SPI -介绍 SPI&#xff08;Serial Peripheral Interface&#xff09;串行外围设备接口。是由Motorola公司开发&#xff0c;用来在微控制器和外围设备芯片之间提供一个低成本&#xff0c;易使用的接口。这样接口可以用来连接存储器、AD转换器、DA转换器、实时时钟、LCD驱动器、…

在大型语言模型(LLM)框架内Transformer架构与混合专家(MoE)策略的概念整合

文章目录 传统的神经网络框架存在的问题一. Transformer架构综述1.1 transformer的输入1.1.1 词向量1.1.2 位置编码&#xff08;Positional Encoding&#xff09;1.1.3 编码器与解码器结构1.1.4 多头自注意力机制 二.Transformer分步详解2.1 传统词向量存在的问题2.2 详解编解码…

GRU 和 LSTM 公式推导与矩阵变换过程图解

GRU 和 LSTM 公式推导与矩阵变换过程图解 GRULSTM 本文的前置篇链接: 单向/双向&#xff0c;单层/多层RNN输入输出维度问题一次性解决 GRU GRU&#xff08;Gate Recurrent Unit&#xff09;是循环神经网络&#xff08;RNN&#xff09;的一种&#xff0c;可以解决RNN中不能长期…

Redis存储⑤Redis五大数据类型之 List 和 Set。

目录 1. List 列表 1.1 List 列表常见命令 1.2 阻塞版本命令 1.3 List命令总结和内部编码 1.4 List典型使用场景 1.4.1 消息队列 1.4.2 分频道的消息队列 1.4.3 微博 Timeline 2. Set 集合 2.1 Set 集合常见命令 2.2 Set 集合间命令 2.3 Set命令小结和内部编码 2.…

JS实现灯光闪烁效果

在 JS中&#xff0c;我们可以实现灯光闪烁效果&#xff0c;这里主要用 setInterval 和 clearInterval 两个重要方法。 效果图 源代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>灯闪烁效果<…

RuoYi-Vue-Oracle的oracle driver驱动配置问题ojdbc8-12.2.0.1.jar的解决

RuoYi-Vue-Oracle的oracle driver驱动配置问题ojdbc8-12.2.0.1.jar的解决 1、报错情况 下载&#xff1a;https://gitcode.com/yangzongzhuan/RuoYi-Vue-Oracle 用idea打开&#xff0c;启动&#xff1a; 日志有报错&#xff1a; 点右侧m图标&#xff0c;maven有以下报误 &…

存储异常导致的Oracle重大生产故障

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 作者&#xff1a;IT邦德 中国DBA联盟(ACDU)成员&#xff0c;10余年DBA工作经验 Oracle、PostgreSQL ACE CSDN博客专家及B站知名UP主&#xff0c;全网粉丝10万 擅长主流Oracle、MySQL、PG、高斯…

【论文翻译】DeepSeek-V3论文翻译——DeepSeek-V3 Technical Report——第一部分:引言与模型架构

论文原文链接&#xff1a;DeepSeek-V3/DeepSeek_V3.pdf at main deepseek-ai/DeepSeek-V3 GitHub 特别声明&#xff0c;本文不做任何商业用途&#xff0c;仅作为个人学习相关论文的翻译记录。本文对原文内容直译&#xff0c;一切以论文原文内容为准&#xff0c;对原文作者表示…

基于Java的远程视频会议系统(源码+系统+论文)

第一章 概述 1.1 本课题的研究背景 随着人们对视频和音频信息的需求愈来愈强烈&#xff0c;追求远距离的视音频的同步交互成为新的时尚。近些年来&#xff0c;依托计算机技术、通信技术和网络条件的发展&#xff0c;集音频、视频、图像、文字、数据为一体的多媒体信息&#xff…

【大模型】DeepSeek与chatGPT的区别以及自身的优势

目录 一、前言二、核心技术对比2.1 模型架构设计2.1.1 ChatGPT的Transformer架构2.1.2 DeepSeek的混合架构 2.2 训练数据体系2.2.1 ChatGPT的数据特征2.2.2 DeepSeek的数据策略 三、应用场景对比3.1 通用场景表现3.1.1 ChatGPT的强项领域3.2.2 DeepSeek的专项突破 3.3 响应效率…

20.<Spring图书管理系统①(登录+添加图书)>

PS&#xff1a;关于接口定义 接口定义&#xff0c;通常由服务器提供方来定义。 1.路径&#xff1a;自己定义 2.参数&#xff1a;根据需求考虑&#xff0c;我们这个接口功能完成需要哪些信息。 3.返回结果&#xff1a;考虑我们能为对方提供什么。站在对方角度考虑。 我们使用到的…