如何使用 NodeJS、Socket.IO 和 MongoDB 构建实时聊天应用程序

2025-05-26

如何使用 NodeJS、Socket.IO 和 MongoDB 构建实时聊天应用程序

如何使用 NodeJS、Socket.IO 和 MongoDB 构建实时聊天应用程序

在本教程中,我们将使用 NodeJS、Express、Socket.io 和 MongoDB 构建实时聊天应用程序。

以下是我们将要构建的内容的屏幕截图:

替代文本

设置

我假设你已经安装了 NodeJS 和 NPM。如果你还没有安装,可以从Node JS官网安装。

需要具备 Javascript 的基本知识。

让我们开始吧。

为应用程序创建一个目录,并使用您喜欢的编辑器(例如 Visual Studio Code)打开该目录。您可以使用任何其他编辑器,在本教程中,我将使用 VS Code:



mkdir chatApplication && cd chatApplication && code . 


Enter fullscreen mode Exit fullscreen mode

接下来,我们将目录初始化为 Nodejs 应用程序。



 npm init 


Enter fullscreen mode Exit fullscreen mode

系统会提示您填写一些信息——没关系。这些信息将用于设置您的package.json文件。

依赖项安装

让我们安装应用程序的依赖项。

我们将使用expressWeb 服务器来提供静态文件,并body-parser提取传入请求流的整个主体部分,并将其公开给 API 端点。所以,让我们安装它们。您将在本教程的后面部分看到它们的使用方法。



 npm install express body-parser --save 


Enter fullscreen mode Exit fullscreen mode

我们添加了 --save 标志,以便将其作为依赖项添加到我们的package.json文件中。

笔记:

请不要使用快速生成器,因为我不会介绍如何配置socket.io以使用快速生成器设置。

接下来,安装 mongoose 节点模块。它是 MongoDB 的对象文档映射器 (ODM),它可以使我们的工作更加轻松。

让我们将它与 socket.io 和 bluebird 一起安装。Socket.IO 是一个用于实时 Web 应用程序的 JavaScript 库。Bluebird一个功能齐全的 JavaScript Promise 库。



 npm install mongoose socket.io bluebird --save 


Enter fullscreen mode Exit fullscreen mode

这就是 Nodejs 后端模块的安装。

我们的package.json文件现在应该是这样的。



{
    "name": "chatApplication",
    "version": "1.0.0",
    "description": "",
    "main": "app.js",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node app"
    },
    "author": "",
    "license": "ISC",
    "dependencies": {
        "bluebird": "^3.5.3",
        "body-parser": "^1.18.3",
        "express": "^4.16.4",
        "mongoose": "^5.4.14",
        "socket.io": "^2.2.0"
    }
}


Enter fullscreen mode Exit fullscreen mode

安装上述软件包的另一种方法是复制package.json上述文件并将其粘贴到您的package.json文件中并运行:



npm install


Enter fullscreen mode Exit fullscreen mode

它将安装所有必需的软件包。

让我们设置客户端。



<!doctype  html>
<html>
    <head>
        <title>Anonymouse Real-time chat</title>
        <link  href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css"  rel="stylesheet"  id="bootstrap-css">
        <!------ Include the above in your HEAD tag ---------->
        <link  href="/css/style.css"  type="text/css"  rel="stylesheet"/>
    </head>
<body>
<div  class="chat_window">
    <div  class="top_menu">
    <div  class="buttons">
    <div  class="button close"></div>
    <div  class="button minimize"></div>
    <div  class="button maximize"></div>
</div>
    <div  class="title">Chat</div>
</div>
    <ul id="messages"  class="messages"></ul>
<div  class="bottom_wrapper clearfix">
<i  id="typing"></i>
    <form  id="form">
        <div  class="message_input_wrapper">
        <input  id="message"  class="message_input"  placeholder="Type your message here..."  />
        </div>
        <button  class="send_message">Send</button>
    </form>
</div>
</div>
<script  src="/js/socket.js"></script>
<script  src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
<script  src="https://cdn.jsdelivr.net/gh/rexeze/formatTimeStamp/src/index.min.js"></script>
<script  src="/js/chat.js"></script>
</body>
</html>


Enter fullscreen mode Exit fullscreen mode

为了将 Socket.IO 服务器连接到客户端,我们添加了 Socket.IO 客户端 javascript 库。



<script  src="/js/socket.js"></script>


Enter fullscreen mode Exit fullscreen mode

这就是我们前端的 html 文件。你可以在这里获取前端的完整代码来继续学习。最好的学习方法就是跟着做。

您可以在此处下载客户端 socket.io 库

这里/js/chat.js就是我们自定义的客户端 JavaScript 代码。

设置我们的快速服务器:

创建一个App.js。你可以将其命名为 server.js,
个人偏好命名为 App.js。

在 App.js 文件中,让我们创建并配置 express 服务器以与 socket.io 一起工作。

App.js



//Require the express moule
const express = require(express);

//create a new express application
const app = express()

//require the http module
const http = require(http).Server(app)

// require the socket.io module
const io = require(socket.io);

const port = 500;

const socket = io(http);
//create an event listener

//To listen to messages
socket.on(connection, (socket)=>{
console.log(user connected);
});

//wire up the server to listen to our port 500
http.listen(port, ()=>{
console.log(connected to port: + port)
});


Enter fullscreen mode Exit fullscreen mode

这是在后端设置 socket.io 所需的基本配置。

Socket.IO 的工作原理是向实例添加事件监听器,http.Server
这就是我们在这里所做的:



const socket = io(http);


Enter fullscreen mode Exit fullscreen mode

这是我们监听新连接事件的地方:



socket.on(connection, (socket)=>{
console.log(user connected);
});


Enter fullscreen mode Exit fullscreen mode

例如,如果新用户访问 localhost:500,则控制台上将打印消息“用户已连接”。

socket.on() 接受事件名称和回调作为参数。

并且还有一个特殊的断开事件,每次用户关闭选项卡时都会触发。



socket.on(connection, (socket)=>{
    console.log(user connected);
    socket.on("disconnect", ()=>{
    console.log("Disconnected")
})
});


Enter fullscreen mode Exit fullscreen mode

设置我们的前端代码

打开js/chat.js文件并输入以下代码:



(function() {
    var  socket  =  io();
    $("form").submit(function(e) {
        e.preventDefault(); // prevents page reloading
        socket.emit("chat message", $("#m").val());
        $("#m").val("");
    return  true;
});
})();


Enter fullscreen mode Exit fullscreen mode

这是一个自执行函数,它在客户端初始化 socket.io 并发出输入框中输入的消息。

通过这行代码,我们在前端创建了soicket.io客户端的全局实例。



 var  socket  =  io();


Enter fullscreen mode Exit fullscreen mode

在提交事件处理程序中,socket io 从文本框获取聊天内容并将其发送到服务器。



$("form").submit(function(e) {
    e.preventDefault(); // prevents page reloading
    socket.emit("chat message", $("#m").val());
    $("#m").val("");
 return  true;
});


Enter fullscreen mode Exit fullscreen mode

如果你已经到达了这一点,那么恭喜你,你值得获得一些赞誉
。😄

太棒了,我们的 express 和 socket.io 服务器都设置好了,运行正常。事实上,我们已经能够通过输入框发送消息到服务器了。



socket.emit("chat message", $("#m").val());


Enter fullscreen mode Exit fullscreen mode

现在让我们从服务器端设置一个事件来监听“聊天消息”事件并将其广播到连接在端口 500 上的客户端。

App.js



socket.on("chat message", function(msg) {
console.log("message: "  +  msg);
//broadcast message to everyone in port:5000 except yourself.
socket.broadcast.emit("received", { message: msg  });
});
});



Enter fullscreen mode Exit fullscreen mode

这是监听“聊天消息”事件的事件处理程序,收到的消息位于传递给回调函数的参数中。



socket.on("chat message", function(msg){
});


Enter fullscreen mode Exit fullscreen mode

在这个事件中,我们可以选择如何处理来自客户端的消息——将其插入数据库,将其发送回客户端等。

在我们的例子中,我们将把它保存到数据库中并将其发送给客户端。

我们会广播它。这意味着服务器会将其发送给除发送者之外连接到服务器的所有其他用户。

因此,如果 A 先生将消息发送到服务器并且服务器广播该消息,则 B、C、D 先生等将收到该消息,但 A 先生不会收到。

我们不想收到自己发送的消息,对吧?😭

这并不意味着我们不能接收我们发送的消息。如果我们删除广播标志,我们也会删除该消息。

广播事件的方法如下:



socket.broadcast.emit("received",{message:msg})


Enter fullscreen mode Exit fullscreen mode

解决了这个问题后,我们就可以接收消息并将其附加到我们的 UI 中。

如果你运行你的应用程序,你应该会看到类似这样的内容。请不要嘲笑我的在线聊天。❤️

哇喔!再次恭喜!让我们添加一些数据库内容并在前端显示聊天内容。

数据库设置

安装 MongoDB

如果您还没有下载,请访问mongoDB网站进行下载。

确保你的 MongoDB 服务器正在运行。他们有一份非常优秀的文档,详细介绍了如何设置、启动和运行它。你可以在这里找到文档。

创建聊天模式

在模型目录中创建一个名为models/ChatSchema.js
“没什么复杂的”的文件,我们的模式中只有 3 个字段——消息字段、发件人字段和时间戳。

ChatSchema.js文件应如下所示:




const  mongoose  = require("mongoose");
const  Schema  =  mongoose.Schema;
const  chatSchema  =  new Schema(
    {
    message: {
    type: String
    },
    sender: {
    type: String
        }
    },
        {
    timestamps: true
});

let  Chat  =  mongoose.model("Chat", chatSchema);
module.exports  =  Chat;



Enter fullscreen mode Exit fullscreen mode

连接到 mongodb 数据库

创建一个文件并将其命名为dbconnection.js。这就是我们的数据库连接所在的位置。



const  mongoose  = require("mongoose");
mongoose.Promise  = require("bluebird");
const  url  =  "mongodb://localhost:27017/chat";
const  connect  =  mongoose.connect(url, { useNewUrlParser: true  });
module.exports  =  connect;


Enter fullscreen mode Exit fullscreen mode

将消息插入数据库

由于我们要在服务器端插入消息,因此我们将把从前端收到的消息插入到App.js文件中。

因此,让我们更新 App.js 文件。




...
//database connection
const  Chat  = require("./models/Chat");
const  connect  = require("./dbconnect");



Enter fullscreen mode Exit fullscreen mode



//setup event listener
socket.on("connection", socket  =>  {
    console.log("user connected");
    socket.on("disconnect", function() {
    console.log("user disconnected");
    });  
    socket.on("chat message", function(msg) {
        console.log("message: "  +  msg);
        //broadcast message to everyone in port:5000 except yourself.
    socket.broadcast.emit("received", { message: msg  });

    //save chat to the database
    connect.then(db  =>  {
    console.log("connected correctly to the server");

    let  chatMessage  =  new Chat({ message: msg, sender: "Anonymous"});
    chatMessage.save();
    });
    });
});



Enter fullscreen mode Exit fullscreen mode

我们正在创建一个新文档并将其保存到数据库的聊天集合中。




    let  chatMessage  =  new Chat({ message: msg, sender: "Anonymous"});
    chatMessage.save();



Enter fullscreen mode Exit fullscreen mode

在前端显示消息

首先,我们将显示数据库中的消息历史记录,并附加事件发出的所有消息。

为了实现这一点,我们需要创建一个 API,当我们发送 get 请求时,将数据从数据库发送到客户端。



const  express  = require("express");
const  connectdb  = require("./../dbconnect");
const  Chats  = require("./../models/Chat");

const  router  =  express.Router();

router.route("/").get((req, res, next) =>  {
        res.setHeader("Content-Type", "application/json");
        res.statusCode  =  200;
        connectdb.then(db  =>  {
            Chats.find({}).then(chat  =>  {
            res.json(chat);
        });
    });
});

module.exports  =  router;


Enter fullscreen mode Exit fullscreen mode

在上面的代码中,我们查询数据库并获取聊天集合中的所有消息。

我们将把它导入到服务器代码中App.js file,并且我们还将导入 bodyparser 中间件。



const  bodyParser  = require("body-parser");
const  chatRouter  = require("./route/chatroute");

//bodyparser middleware
app.use(bodyParser.json());

//routes
app.use("/chats", chatRouter);


Enter fullscreen mode Exit fullscreen mode

解决了这个问题后,我们就可以从前端访问我们的 API 并获取聊天集合中的所有消息。



// fetching initial chat messages from the database
(function() {
    fetch("/chats")
    .then(data  =>  {
    return  data.json();
    })
.then(json  =>  {
json.map(data  =>  {
let  li  =  document.createElement("li");
let messages = docuemtn.getElementById("messages")
let  span  =  document.createElement("span");
messages.appendChild(li).append(data.message);

    messages
    .appendChild(span)
    .append("by "  +  data.sender  +  ": "  +  formatTimeAgo(data.createdAt));
});
});
})();


Enter fullscreen mode Exit fullscreen mode

因此,我们使用 fetch API 获取消息并将消息附加到 UI。

您还会注意到,我使用了formatTimeAgo(data.createdAt));一个 1.31kb 的库,用于管理小型项目的日期,因为 moment.js 有时太大了。formatTimeAgo() 将显示“几秒钟前”等。

如果您有兴趣,可以在这里找到更多信息。

目前看来一切都很好,对吗?

但是,由于您没有收到发送到服务器并返回给您自己的消息,因此让我们从输入框中获取我们自己的消息并将其显示在 UI 上。



(function() {
$("form").submit(function(e) {
    let  li  =  document.createElement("li");
    e.preventDefault(); // prevents page reloading
    socket.emit("chat message", $("#message").val());
    messages.appendChild(li).append($("#message").val());
    let  span  =  document.createElement("span");
    messages.appendChild(span).append("by "  +  "Anonymous"  +  ": "  +  "just now");
    $("#message").val("");
return  false;

});
})();



Enter fullscreen mode Exit fullscreen mode

而且如果我们从事件收到消息,我们也会将其输出到 UI。



(function(){
socket.on("received", data  =>  {
let  li  =  document.createElement("li");
let  span  =  document.createElement("span");
var  messages  =  document.getElementById("messages");
messages.appendChild(li).append(data.message);
messages.appendChild(span).append("by "  +  "anonymous"  +  ": "  +  "just now");
});
})


Enter fullscreen mode Exit fullscreen mode

我们的应用程序现已完成。继续测试它。

注意,如果用户已经登录,我们就不会像现在这样硬编码“匿名”用户了。我们会从服务器获取它。

另外,如果您想告诉所有人有人正在输入,您也可以在前端添加此代码。



//isTyping event
messageInput.addEventListener("keypress", () =>  {
socket.emit("typing", { user: "Someone", message: "is typing..."  });
});
socket.on("notifyTyping", data  =>  {
typing.innerText  =  data.user  +  "  "  +  data.message;
console.log(data.user  +  data.message);
});
//stop typing
messageInput.addEventListener("keyup", () =>  {
socket.emit("stopTyping", "");
});
socket.on("notifyStopTyping", () =>  {
typing.innerText  =  "";

});


Enter fullscreen mode Exit fullscreen mode

它的作用是,当用户输入时,它会向服务器发出一个事件,服务器会将该事件广播给其他客户端。您可以监听该事件,并在 UI 中更新消息“有人正在输入……”。如果您愿意,还可以添加输入者的姓名。

这是服务器端事件监听器和发射器:



 //Someone is typing

 socket.on("typing", data => { 

    socket.broadcast.emit("notifyTyping", { user: data.user, message: data.message }); }); 

//when soemone stops typing

socket.on("stopTyping", () => { socket.broadcast.emit("notifyStopTyping"); });


Enter fullscreen mode Exit fullscreen mode

恭喜。

您可以改进此代码,添加身份验证,添加组或使其成为一对一聊天,重新建模模式以适应所有这些,等等。

我非常高兴看到您使用 socket.IO 构建的实时应用程序。

希望以上内容对您有所帮助。完整代码在 Github 上。您可以点击此处获取。

文章来源:https://dev.to/rexeze/how-to-build-a-real-time-chat-app-with-nodejs-socketio-and-mongodb-2kho
PREV
JavaScript 生成器的用例
NEXT
Sublime Text 与 Vscode 对比 我为什么从 Visual Studio Code 切换到 Sublime Text