In this tutorial, I will show you how to implement a real-time chat application using Node.js, Socket.IO and MongoDB, and then we will deploy the application together to Modulus.
First, let me show you the final look of the application that we will see at the end of the article.
Node.js will be the core of the application, Express as MVC, MongoDB as database, Socket. IO is used for real-time communication. Once completed, we will deploy the application to Modulus. The MongoDB part actually lives inside Modulus.
As you can see, this is a very simple application, but it covers almost everything a web application has to offer. There is no channel system in the application, but you can fork the source code and implement the channel module to practice.
I will try to explain the small parts of the project first and then put them together at the end. I'll start with the backend and work my way up to the frontend. So, let's start with the domain objects (MongoDB models).
For database abstraction, we will use Mongoose. In this project, we have only one model named Message
. This message model only contains text
, createDate
, and author
. The author does not have a model like User
, because we will not fully implement the user registration/login system. There will be a simple nickname providing page, and the nickname will be saved to a cookie. This will be used in the Message
model as the text in the author
field. You can see a sample JSON model below:
{ text: "Hi, is there any Full Stack Developer here?" author: "john_the_full_stack", createDate: "2015.05.15" }
To create such a document, you can use the following Mongoose function to implement the model:
var mongoose = require('mongoose') var Message = new mongoose.Schema({ author: String, message: String, createDate: { type: Date, default: Date.now } }); mongoose.model('Message', Message)
Simply import the Mongoose module, define the model with fields and field properties in JSON format, and create a model named Message
. The model will be included in the page you want to use.
Maybe you have questions, why do we store the message in the database when we are already broadcasting this message to the users in the same channel. It's true that you don't have to store chat messages, but I just wanted to explain the database integration layer. Anyway, we will use this model in the controller in our project. Controller?
As I said before, we will use Express for the MVC part. And C
here represents Controller
. For our project, there are only two messaging endpoints. One of them is loading recent chat messages and the second one is handling sent chat messages which are stored in database and then broadcast to the channel.
..... app.get('/chat', function(req, res){ res.sendFile(__dirname + '/index.html'); }); app.get('/login', function(req, res){ res.sendFile(__dirname + '/login.html'); }); app.post('/messages', function(req, res, next) { var message = req.body.message; var author = req.body.author; var messageModel = new Message(); messageModel.author = author; messageModel.message = message; messageModel.save(function (err, result) { if (!err) { Message.find({}).sort('-createDate').limit(5).exec(function(err, messages) { io.emit("message", messages); }); res.send("Message Sent!"); } else { res.send("Technical error occurred!"); } }); }); app.get('/messages', function(req, res, next) { Message.find({}).sort('-createDate').limit(5).exec(function(err, messages) { res.json(messages); }); }); .....
The first and second controllers are only used to serve static HTML files for the chat and login pages. The third is used to handle publish requests to the /messages
endpoint to create new messages. In this controller, first convert the request body into a Message model and then use the Mongoose function save
.
I won't delve into Mongoose - you can check out the documentation for more details. You can provide a callback function to the save function to check if there are any problems. If successful, we will get the last 5 records in descending order by createDate
and broadcast 5 messages to the clients in the channel.
Okay, we're done MC
. Let’s switch to the View
section.
Generally speaking, template engines such as Jade, EJS, and Handlebars can be used in Express. However, we only have one page, and that's a chat message, so I'm going to serve it statically. Actually, as I said above, there are two more controllers serving this static HTML page. You can see the following is used to serve a static HTML page.
app.get('/chat', function(req, res){ res.sendFile(__dirname + '/index.html'); }); app.get('/login', function(req, res){ res.sendFile(__dirname + '/login.html'); });
This endpoint only serves index.html and login.html using res.sendFile
. index.html and login.html are in the same folder as server.js, that's why we use __dirname
before the HTML file name.
在前端页面中,我已经使用了Bootstrap,无需解释我是如何做到这一点的。简单来说,我将一个函数绑定到一个文本框,每当您按下Enter键或发送按钮时,消息就会发送到后端服务。
该页面还有一个必需的Socket.IO js文件,用于监听名为message
的频道。 Socket.IO 模块已在后端导入,当您在服务器端使用此模块时,它会自动添加一个端点来提供 Socket.IO js 文件,但我们使用由 cdn <script src="https://cdn.socket.io/socket.io-1.3.5.js"></script>
。每当有新消息进入此频道时,都会自动检测到该消息,并且消息列表将刷新为最后 5 条消息。
<script> var socket = io(); socket.on("message", function (messages) { refreshMessages(messages); }); function refreshMessages(messages) { $(".media-list").html(""); $.each(messages.reverse(), function(i, message) { $(".media-list").append('<li class="media"><div class="media-body"><div class="media"><div class="media-body">' + message.message + '<br/><small class="text-muted">' + message.author + ' | ' + message.createDate + '</small><hr/></div></div></div></li>'); }); } $(function(){ if (typeof $.cookie("realtime-chat-nickname") === 'undefined') { window.location = "/login" } else { $.get("/messages", function (messages) { refreshMessages(messages) }); $("#sendMessage").on("click", function() { sendMessage() }); $('#messageText').keyup(function(e){ if(e.keyCode == 13) { sendMessage(); } }); } function sendMessage() { $container = $('.media-list'); $container[0].scrollTop = $container[0].scrollHeight; var message = $("#messageText").val(); var author = $.cookie("realtime-chat-nickname"); $.post( "/messages", {message: message, author: author}, function( data ) { $("#messageText").val("") }); $container.animate({ scrollTop: $container[0].scrollHeight }, "slow"); } }) </script>
上面的代码中还有一项检查:cookie 部分。如果您没有选择任何聊天昵称,则表示该昵称没有设置cookie,您将自动重定向到登录页面。
如果没有,最后五条消息将通过对 /messages
端点的简单 Ajax 调用来获取。同样,每当您点击发送按钮或按Enter键时,都会从文本框中提取短信,并从文本框中提取昵称。 cookie,这些值将通过 post 请求发送到服务器。这里没有严格检查昵称,因为我想关注实时部分,而不是用户身份验证部分。
正如你所看到的,项目的整体结构非常简单。让我们进入部署部分。正如我之前所说,我们将使用 Modulus,它是用您选择的语言部署、扩展和监控应用程序的最佳 PaaS 之一。
我首先想到的是向您展示如何部署,但为了成功部署,我们需要一个工作数据库。我们来看看如何在Modulus上创建数据库,然后进行部署。
创建帐户后转至 Modulus 仪表板。点击左侧的数据库菜单,然后点击创建数据库。
在弹出表单中填写必填字段,如下所示。
当您填写必填字段并点击创建时,它将创建一个 MongoDB 数据库您将在屏幕上看到您的数据库 URL。我们将使用 MONGO URI, 因此请复制该 URI。
在我们的项目中,Mongo URI是从环境变量MONGO_URI
中获取的,您需要在仪表板中设置该环境变量。转到信息中心,点击项目菜单,在列表中选择您的项目,然后点击左侧菜单中的管理。在此页面中,向下滚动页面时您将看到环境变量部分,如下所示。
您可以通过两种方式部署到 Modulus:
我将继续使用命令行选项,因为另一个很容易做到。首先,安装 Modulus CLI:
npm install -g modulus
转到您的项目文件夹并执行以下命令以登录 Modulus。
modulus login
当您执行上述命令时,系统会提示您输入用户名和密码:
如果您已使用 GitHub 创建帐户,则可以使用 --github
选项.
modulus login --github
现在您已登录 Modulus,可以创建项目了。使用以下命令创建项目:
modulus project create "Realtime Chat"
当您运行此函数时,系统会询问您运行时。选择第一个选项,即 Node.js,第二个选项将询问您伺服器的大小,您可以保留默认值。
我们已经创建了一个项目,这次我们将把当前项目部署到Modulus中。执行以下命令将当前项目发送到Modulus端的Realtime Chat项目中。
modulus deploy
它将部署您的项目,并且您将在成功部署消息的末尾获得正在运行的项目 URL:
Realtime Chat running at realtime-chat-46792.onmodulus.net
如您所见,部署到 Modulus 非常简单!
The Modulus CLI has very useful commands that can be used during project deployment or runtime. For example, to track the logs of a running project, you can use modulus project log tail
, to create a MongoDB database use modulus mongo create <db-name></db-name>
, and to set environment variables, use modulus env set <key> <value></value></key>
etc. You can use Modulus Help to see the complete list of commands.
The main purpose of this tutorial is to show you how to create a real-time chat application using Node.js, Socket.IO and MongoDB. To run the project in production, Modulus is used as a PaaS provider. The deployment steps for Modulus are very simple, and it also provides an internal database (MongoDB) for our project. Apart from this, you can also use very useful tools like logging, notifications, autoscaling, database management, etc. in the Modulus dashboard.
To sign up for Modulus, click here and get an extra $10 by becoming a Tuts reader. Use promo code ModulusChat10.
For more information about Modulus enterprise products, click here.
The above is the detailed content of Live Chat: Implemented using Modulus and Node.js. For more information, please follow other related articles on the PHP Chinese website!