如何使用 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 .
接下来,我们将目录初始化为 Nodejs 应用程序。
npm init
系统会提示您填写一些信息——没关系。这些信息将用于设置您的package.json
文件。
依赖项安装
让我们安装应用程序的依赖项。
我们将使用express
Web 服务器来提供静态文件,并body-parser
提取传入请求流的整个主体部分,并将其公开给 API 端点。所以,让我们安装它们。您将在本教程的后面部分看到它们的使用方法。
npm install express body-parser --save
我们添加了 --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
这就是 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"
}
}
安装上述软件包的另一种方法是复制package.json
上述文件并将其粘贴到您的package.json
文件中并运行:
npm install
它将安装所有必需的软件包。
让我们设置客户端。
<!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>
为了将 Socket.IO 服务器连接到客户端,我们添加了 Socket.IO 客户端 javascript 库。
<script src="/js/socket.js"></script>
这就是我们前端的 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)
});
这是在后端设置 socket.io 所需的基本配置。
Socket.IO 的工作原理是向实例添加事件监听器,http.Server
这就是我们在这里所做的:
const socket = io(http);
这是我们监听新连接事件的地方:
socket.on(“connection”, (socket)=>{
console.log(“user connected”);
});
例如,如果新用户访问 localhost:500,则控制台上将打印消息“用户已连接”。
socket.on() 接受事件名称和回调作为参数。
并且还有一个特殊的断开事件,每次用户关闭选项卡时都会触发。
socket.on(“connection”, (socket)=>{
console.log(“user connected”);
socket.on("disconnect", ()=>{
console.log("Disconnected")
})
});
设置我们的前端代码
打开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;
});
})();
这是一个自执行函数,它在客户端初始化 socket.io 并发出输入框中输入的消息。
通过这行代码,我们在前端创建了soicket.io客户端的全局实例。
var socket = io();
在提交事件处理程序中,socket io 从文本框获取聊天内容并将其发送到服务器。
$("form").submit(function(e) {
e.preventDefault(); // prevents page reloading
socket.emit("chat message", $("#m").val());
$("#m").val("");
return true;
});
如果你已经到达了这一点,那么恭喜你,你值得获得一些赞誉
。😄
太棒了,我们的 express 和 socket.io 服务器都设置好了,运行正常。事实上,我们已经能够通过输入框发送消息到服务器了。
socket.emit("chat message", $("#m").val());
现在让我们从服务器端设置一个事件来监听“聊天消息”事件并将其广播到连接在端口 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 });
});
});
这是监听“聊天消息”事件的事件处理程序,收到的消息位于传递给回调函数的参数中。
socket.on("chat message", function(msg){
});
在这个事件中,我们可以选择如何处理来自客户端的消息——将其插入数据库,将其发送回客户端等。
在我们的例子中,我们将把它保存到数据库中并将其发送给客户端。
我们会广播它。这意味着服务器会将其发送给除发送者之外连接到服务器的所有其他用户。
因此,如果 A 先生将消息发送到服务器并且服务器广播该消息,则 B、C、D 先生等将收到该消息,但 A 先生不会收到。
我们不想收到自己发送的消息,对吧?😭
这并不意味着我们不能接收我们发送的消息。如果我们删除广播标志,我们也会删除该消息。
广播事件的方法如下:
socket.broadcast.emit("received",{message:msg})
解决了这个问题后,我们就可以接收消息并将其附加到我们的 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;
连接到 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;
将消息插入数据库
由于我们要在服务器端插入消息,因此我们将把从前端收到的消息插入到App.js
文件中。
因此,让我们更新 App.js 文件。
...
//database connection
const Chat = require("./models/Chat");
const connect = require("./dbconnect");
//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();
});
});
});
我们正在创建一个新文档并将其保存到数据库的聊天集合中。
let chatMessage = new Chat({ message: msg, sender: "Anonymous"});
chatMessage.save();
在前端显示消息
首先,我们将显示数据库中的消息历史记录,并附加事件发出的所有消息。
为了实现这一点,我们需要创建一个 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;
在上面的代码中,我们查询数据库并获取聊天集合中的所有消息。
我们将把它导入到服务器代码中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);
解决了这个问题后,我们就可以从前端访问我们的 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));
});
});
})();
因此,我们使用 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;
});
})();
而且如果我们从事件收到消息,我们也会将其输出到 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");
});
})
我们的应用程序现已完成。继续测试它。
注意,如果用户已经登录,我们就不会像现在这样硬编码“匿名”用户了。我们会从服务器获取它。
另外,如果您想告诉所有人有人正在输入,您也可以在前端添加此代码。
//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 = "";
});
它的作用是,当用户输入时,它会向服务器发出一个事件,服务器会将该事件广播给其他客户端。您可以监听该事件,并在 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"); });
恭喜。
您可以改进此代码,添加身份验证,添加组或使其成为一对一聊天,重新建模模式以适应所有这些,等等。
我非常高兴看到您使用 socket.IO 构建的实时应用程序。
希望以上内容对您有所帮助。完整代码在 Github 上。您可以点击此处获取。
文章来源:https://dev.to/rexeze/how-to-build-a-real-time-chat-app-with-nodejs-socketio-and-mongodb-2kho