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>
整体项目目录
部署到服务器
这里大家自行部署到服务器就行,给你的好友展示一下。如果有需要部署教程的 等有时间出个部署教程
相关文章:

node.js + html + Sealos容器云 搭建简易多人实时聊天室demo 带源码
node.js html Sealos容器云 搭建简易多人实时聊天室demo 带源码 前言功能介绍(demo演示)sealos官网配置node.js 编写服务端代码前端ui 调用接口整体项目目录部署到服务器 前言 hello哦盆友们,这次我们来十几行代码做一个超简单的多人聊天…...

OpenFeign远程调用返回的是List<T>类型的数据
在使用 OpenFeign 进行远程调用时,如果接口返回的是 List 类型的数据,可以通过以下方式处理: 直接定义返回类型为List Feign 默认支持 JSON 序列化/反序列化,如果服务端返回的是 List的JSON格式数据,可以直接在 Feig…...

PCL 计算多边形的面积【2025最新版】
目录 一、算法原理1、概述2、主要函数3、函数源码二、代码实现三、结果展示博客长期更新,本文最近更新时间为:2025年1月17日。 一、算法原理 1、概述 根据给定的多边形的点云计算多边形的面积 A r e a = 1 2 ∑...

著名大模型评测榜单(不同评测方式)
在评估大语言模型的性能时,一种主流的途径就是选择不同的能力维度并且构建对应的评测任务,进而使用这些能力维度的评测任务对模型的性能进行测试与对比。由大型机构或者研究院所排出榜单。 评测指标 不同评测任务有不同的评指标,衡量模型的…...

国内知名Deepseek培训师培训讲师唐兴通老师讲授AI人工智能大模型实践应用
课程名称 《Deepseek人工智能大模型实践应用》 课程目标 全面了解Deepseek人工智能大模型的技术原理、功能特点及应用场景。 熟练掌握Deepseek大模型的提示词工程技巧,能够编写高质量的提示词。 掌握Deepseek大模型在办公、营销等领域的应用方法,提升…...

【AIGC】冷启动数据与多阶段训练在 DeepSeek 中的作用
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AIGC | ChatGPT 文章目录 💯前言💯冷启动数据的作用冷启动数据设计 💯多阶段训练的作用阶段 1:冷启动微调阶段 2:推理导向强化学习(RL࿰…...

如何打造一个更友好的网站结构?
在SEO优化中,网站的结构往往被忽略,但它其实是决定谷歌爬虫抓取效率的关键因素之一。一个清晰、逻辑合理的网站结构,不仅能让用户更方便地找到他们需要的信息,还能提升搜索引擎的抓取效率 理想的网站结构应该像一棵树,…...
【ROS2】RViz2自定义面板插件(rviz_common::Panel)的详细步骤
【ROS】郭老二博文之:ROS目录 1、简述 RViz2 的插件基于 ROS2 的插件库(pluginlib)机制,通过动态加载共享库实现功能扩展。 注意:RViz2 使用 QT 作为 UI 框架,虽然 QT 也有插件机制,但是 RViz2 并没有使用QT的插件机制,而是通过 pluginlib 加载功能模块来实现。 2、…...

漏洞分析 Spring Framework路径遍历漏洞(CVE-2024-38816)
漏洞概述 VMware Spring Framework是美国威睿(VMware)公司的一套开源的Java、JavaEE应用程序框架。该框架可帮助开发人员构建高质量的应用。 近期,监测到Spring Framework在特定条件下,存在目录遍历漏洞(网宿评分&am…...
《手札·避坑篇》2025年传统制造业企业数字化转型指南
一、引言 在数字化浪潮的推动下,传统制造业企业正加速向智能化、数字化转型。开源软件技术与制造MES(制造执行系统)产品的结合,为企业提供了高效、灵活且低成本的转型路径。本指南旨在为传统制造业企业的信息化负责人提供一套完整的数字化转型方案,助力企业实现高效、智能…...
MySQL中DDL操作是否支持事务
MySQL中DDL不支持事务。 传统MySQL(5.7及以前版本): DDL操作不支持事务执行DDL操作时会隐式提交当前会话的事务无法回滚DDL操作 MySQL 8.0版本: 引入了原子DDL特性(Atomic DDL)DDL操作变为原子性的&…...

GWO优化决策树回归预测matlab
灰狼优化算法(Grey Wolf Optimizer,简称 GWO)是一种群智能优化算法,由澳大利亚格里菲斯大学的 Mirjalii 等人于 2014 年提出。该算法的设计灵感源自灰狼群体的捕食行为,核心思想是模仿灰狼社会的结构与行为模式。 在本…...

掌握Spring @SessionAttribute:跨请求数据共享的艺术
SessionAttribute注解在Spring中的作用,就像是一个“数据中转站”。 在Web应用中,我们经常需要在多个请求之间共享数据。比如,用户登录后,我们需要在多个页面或请求中保持用户的登录状态。这时,SessionAttribute注解就…...

python读取Excel表格内公式的值
背景:在做业务周报的时候,有一个Excel模板,表里面包含了一些公式,dataframe写入到Excel的时候,有公式的部分通过python读出来的结果是None,需要进行优化参考链接: 如何使用openpyxl读取Excel单元…...
第三十八章:阳江自驾之旅:挖蟹与品鲜
经历了惠州海边那趟温馨又欢乐的自驾之旅后,小冷和小颖心中对旅行的热情愈发高涨。闲暇时,两人总会坐在客厅里,翻看着旅行杂志,或是在网上搜索各地的美景,那些充满魅力的地方不断吸引着他们,也让他们对下一…...

C++小等于的所有奇数和=最大奇数除2加1的平方。
缘由 三种思路解题:依据算术推导得到一个规律:小等于的所有奇数和等于最大奇数除以2加1的平方。将在后续发布,总计有十种推导出来的实现代码。 int a 0,aa 1,aaa 0;cin >> a; while (aa<a) aaa aa, aa 2;cout << aaa;i…...

设置IDEA的内存大小,让IDEA更流畅: 建议设置在 2048 MB 及以上
文章目录 引言I 更改内存设置基于窗口界面进行内存设置修改内存配置文件II IDEA中的一些常见问题及其解决方案引言 方式一:基于窗口界面进行内存设置方式二:修改内存配置文件I 更改内存设置 基于窗口界面进行内存设置 打开IDEA,上方菜单栏 Help > Change Memory Settin…...
Ranger Hive Service连接测试失败问题解决
个人博客地址:Ranger Hive Service连接测试失败问题解决 | 一张假钞的真实世界 异常信息如下: org.apache.ranger.plugin.client.HadoopException: Unable to connect to Hive Thrift Server instance.. Unable to connect to Hive Thrift Server inst…...
车机音频参数下发流程
比如以audioControlWrapper.setParametersToAmp(keyPairValues); 下发banlance为例,链路如下 hal层 1. AudioControl.cpp hardware\interfaces\automotive\audiocontrol\aidl\default\AudioControl.cpp ndk::ScopedAStatus AudioControl::setParametersToAmp(co…...

大模型推理——MLA实现方案
1.整体流程 先上一张图来整体理解下MLA的计算过程 2.实现代码 import math import torch import torch.nn as nn# rms归一化 class RMSNorm(nn.Module):""""""def __init__(self, hidden_size, eps1e-6):super().__init__()self.weight nn.Pa…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...

Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...

C++_哈希表
本篇文章是对C学习的哈希表部分的学习分享 相信一定会对你有所帮助~ 那咱们废话不多说,直接开始吧! 一、基础概念 1. 哈希核心思想: 哈希函数的作用:通过此函数建立一个Key与存储位置之间的映射关系。理想目标:实现…...

《信号与系统》第 6 章 信号与系统的时域和频域特性
目录 6.0 引言 6.1 傅里叶变换的模和相位表示 6.2 线性时不变系统频率响应的模和相位表示 6.2.1 线性与非线性相位 6.2.2 群时延 6.2.3 对数模和相位图 6.3 理想频率选择性滤波器的时域特性 6.4 非理想滤波器的时域和频域特性讨论 6.5 一阶与二阶连续时间系统 6.5.1 …...