В този урок ще ви покажа как да внедрите приложение за чат в реално време с Node.js, Socket.IO и MongoDB, след което ще разгърнем това приложение в Modulus заедно.
Първо, нека ви покажа окончателния вид на приложението, който ще имаме в края на статията.
Node.js ще бъде ядрото на приложението, с Express като MVC, MongoDB за базата данни и Socket.IO за комуникация в реално време. Когато приключим, ще разположим нашето приложение в Modulus. Частта MongoDB всъщност съществува вътре в Modulus.
1. Сценарий
- Джон иска да използва нашето приложение и го отваря в браузъра.
- На първата страница той избира псевдоним, използван по време на чат, и влиза в чата.
- В текстовата област той пише нещо и натиска Enter.
- Текстът се изпраща до услуга RESTful (Express) и този текст се записва в MongoDB.
- Преди да пишете в MongoDB, същият текст ще бъде излъчен на потребителите, които в момента са влезли в приложението за чат.
Както можете да видите, това е много просто приложение, но обхваща почти всичко за уеб приложение. В това приложение няма канална система, но можете да разклоните изходния код и да приложите модула за канали за практика.
2. Проектиране от нулата
Ще се опитам първо да обясня малките части от проекта и да ги комбинирам в края. Ще започна от задния край към предния край. И така, нека започнем с обектите на домейна (модели MongoDB).
2.1. Модел
За абстракция на база данни ще използваме Mongoose. В този проект имаме само един модел, наречен Message
. Този модел на съобщението съдържа само text
, createDate
, и author
. Няма модел за автора като User
, защото няма да приложим напълно система за регистрация/вход на потребител. Ще има проста страница за предоставяне на псевдоним и този псевдоним ще бъде запазен в бисквитка. Това ще се използва в Message
модел като текст в author
поле. Можете да видите примерен JSON модел по-долу:
{ text: "Hi, is there any Full Stack Developer here?" author: "john_the_full_stack", createDate: "2015.05.15" }
За да създадете документи като този, можете да приложите модел, като използвате функциите на Mongoose по-долу:
var mongoose = require('mongoose') var Message = new mongoose.Schema({ author: String, message: String, createDate: { type: Date, default: Date.now } }); mongoose.model('Message', Message)
Просто импортирайте модула Mongoose, дефинирайте своя модел с неговите полета и атрибути на полета във формат JSON и създайте модел с името Message
. Този модел ще бъде включен в страниците, които искате да използвате.
Може би имате въпрос защо съхраняваме съобщението в базата данни, след като вече излъчваме това съобщение до потребителя в същия канал. Вярно е, че не е нужно да съхранявате чат съобщения, но просто исках да обясня слоя за интеграция на базата данни. Както и да е, ние ще използваме този модел в нашия проект вътре в контролерите. Контролери?
2.2. Контролер
Както казах по-рано, ще използваме Express за MVC частта. И C
тук означава Controller
. За нашите проекти ще има само две крайни точки за съобщения. Един от тях е за зареждане на скорошни съобщения за чат, а вторият е за обработка на изпратени чат съобщения, които да се съхраняват в базата данни и след това да се излъчват в канала.
..... 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); }); }); .....
Първият и вторият контролери са само за обслужване на статични HTML файлове за страниците за чат и вход. Третият е за обработка на заявката за публикуване към /messages
крайна точка за създаване на нови съобщения. В този контролер първо тялото на заявката се преобразува в модела на съобщението и след това този модел се записва в базата данни с помощта на функцията Mongoose save
.
Няма да се гмуркам много в Mongoose – можете да разгледате документацията за повече подробности. Можете да предоставите функция за обратно извикване за функцията за запазване, за да проверите дали има някакъв проблем или не. Ако е успешен, извличаме последните пет записа, сортирани в низходящ ред по createDate
, и са излъчили пет съобщения до клиентите в канала.
Добре, приключихме с MC
. Нека преминем към View
част.
2.3. Преглед
Като цяло, шаблонен двигател като Jade, EJS, Handlebars и т.н., може да се използва в Express. Имаме обаче само една страница и това е съобщение за чат, така че ще го обслужвам статично. Всъщност, както казах по-горе, има още два контролера, които да обслужват тази статична HTML страница. Можете да видите следното за обслужване на статична HTML страница.
app.get('/chat', function(req, res){ res.sendFile(__dirname + '/index.html'); }); app.get('/login', function(req, res){ res.sendFile(__dirname + '/login.html'); });
Тази крайна точка просто обслужва index.html и login.html с помощта на res.sendFile
. И двете index.html и login.html са в същата папка като server.js, поради което използвахме __dirname
преди името на HTML файла.
2.4. Преден край
В предната страница използвах Bootstrap и няма нужда да обяснявам как успях да направя това. Просто свързах функция с текстово поле и всеки път, когато натиснете Enter клавиш или Изпращане бутон, съобщението ще бъде изпратено до бек-енд услугата.
Тази страница също има задължителен js файл на Socket.IO за слушане на канала, наречен message
. Модулът Socket.IO вече е импортиран в задния край и когато използвате този модул от страна на сървъра, той автоматично добавя крайна точка за обслужване на Socket.IO js файла, но ние използваме този, който се обслужва от cdn <script src="//cdn.socket.io/socket.io-1.3.5.js"></script>
. Всеки път, когато постъпи ново съобщение в този канал, то автоматично ще бъде открито и списъкът със съобщения ще бъде обновен с последните пет съобщения.
<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>
Има още една проверка в горния код:частта за бисквитки. Ако не сте избрали никакъв псевдоним за чат, това означава, че бисквитката не е зададена за псевдонима и ще бъдете автоматично пренасочени към страницата за вход.
Ако не, последните пет съобщения ще бъдат извлечени чрез просто извикване на Ajax до /messages
крайна точка. По същия начин, когато щракнете върху Изпращане или натиснете Enter ключ, текстовото съобщение ще бъде извлечено от текстовото поле, а псевдонимът ще бъде извлечен от бисквитката и тези стойности ще бъдат изпратени до сървъра със заявка за публикуване. Тук няма строга проверка за псевдонима, защото исках да се съсредоточа върху частта в реално време, а не върху частта за удостоверяване на потребителя.
Както можете да видите, цялостната структура на проекта е много проста. Нека да стигнем до частта за разгръщане. Както казах по-рано, ще използваме Modulus, един от най-добрите PaaS за разгръщане, мащабиране и наблюдение на вашето приложение на езика по ваш избор.
3. Разгръщане
3.1. Предпоставки
Първото нещо, което ми идва на ум, е да ви покажа как се внедрява, но за успешно внедряване се нуждаем от работеща база данни. Нека да разгледаме как да създадем база данни на Modulus и след това да извършим внедряване.
Отидете в таблото за управление на Modulus, след като създадете акаунт. Кликнете върху Бази данни меню вляво и щракнете върху Създаване на база данни.
Попълнете задължителните полета в изскачащия формуляр, както е по-долу.
Когато попълните задължителните полета и кликнете върху Създаване, той ще създаде база данни MongoDB за вас и ще видите URL адреса на вашата база данни на екрана. Ще използваме MONGO URI , така че копирайте този URI.
В нашия проект URI на Mongo се извлича от променливата на средата MONGO_URI
, и трябва да зададете тази променлива на средата в таблото за управление. Отидете на таблото за управление, кликнете върху Проекти меню, изберете вашия проект от списъка и щракнете върху Администриране в лявото меню. На тази страница ще видите секцията за променливи на средата, когато превъртите надолу по страницата, както е показано по-долу.
Можете да внедрите в Modulus по два начина:
- качване на ZIP файла на проекта с помощта на таблото за управление
- разгръщане от командния ред с помощта на Modulus CLI
Ще продължа с опцията за командния ред, защото другата е лесна за изпълнение. Първо, инсталирайте Modulus CLI:
npm install -g modulus
Отидете в папката на вашия проект и изпълнете следната команда, за да влезете в Modulus.
modulus login
Когато изпълните горната команда, ще бъдете подканени да въведете потребителско име и парола:
Ако сте създали акаунт с помощта на GitHub, можете да използвате --github
опция.
modulus login --github
Сега сте влезли в Modulus и е време да създадете проект. Използвайте следната команда, за да създадете проект:
modulus project create "Realtime Chat"
Когато стартирате тази функция, ще бъдете попитани за времето за изпълнение. Изберете първата опция, която е Node.js, и втората ще бъдете попитани за размера на сервото и можете да го запазите по подразбиране.
Създадохме проект и този път ще разположим настоящия ни проект в Modulus. Изпълнете следната команда, за да изпратите текущия проект в Чат в реално време проект от страна на модула.
modulus deploy
Той ще разгърне вашия проект и вие ще получите URL адреса на вашия текущ проект в края на съобщението за успешно внедряване:
Realtime Chat running at realtime-chat-46792.onmodulus.net
Както можете да видите, внедряването в Modulus е много лесно!
Modulus CLI има много полезни команди, които да използвате по време на внедряването на вашия проект или по време на изпълнение. Например, за да следите регистрите на вашия текущ проект, можете да използвате modulus project logs tail
, за да създадете база данни MongoDB използвайте modulus mongo create <db-name>
, за да зададете променлива на средата, използвайте modulus env set <key> <value>
, и т.н. Можете да видите пълен списък с команди, като използвате помощта на Modulus.