In diesem Tutorial zeige ich Ihnen, wie Sie eine Echtzeit-Chat-Anwendung mit Node.js, Socket.IO und MongoDB implementieren, und dann werden wir diese Anwendung gemeinsam auf Modulus bereitstellen.
Lassen Sie mich Ihnen zunächst das endgültige Aussehen der Anwendung zeigen, die wir am Ende des Artikels haben werden.
Node.js wird der Kern der Anwendung sein, mit Express als MVC, MongoDB für die Datenbank und Socket.IO für die Echtzeitkommunikation. Wenn wir fertig sind, werden wir unsere Anwendung auf Modulus bereitstellen. Der MongoDB-Teil existiert tatsächlich innerhalb von Modulus.
1. Szenario
- John möchte unsere Anwendung verwenden und öffnet sie im Browser.
- Auf der ersten Seite wählt er einen Spitznamen aus, der während des Chats verwendet wird, und meldet sich beim Chat an.
- Im Textbereich schreibt er etwas und drückt Enter.
- Der Text wird an einen RESTful-Dienst (Express) gesendet und dieser Text wird in MongoDB geschrieben.
- Vor dem Schreiben in MongoDB wird derselbe Text an die Benutzer gesendet, die derzeit bei der Chat-App angemeldet sind.
Wie Sie sehen können, ist dies eine sehr einfache App, die jedoch fast alles für eine Webanwendung abdeckt. In dieser Anwendung gibt es kein Channel-System, aber Sie können den Quellcode forken und das Channel-Modul zum Üben implementieren.
2. Projektdesign von Grund auf neu
Ich werde versuchen, die kleinen Teile des Projekts zuerst zu erklären und sie am Ende zusammenzufügen. Ich werde vom Backend zum Frontend beginnen. Beginnen wir also mit den Domänenobjekten (MongoDB-Modellen).
2.1. Modell
Für die Datenbankabstraktion verwenden wir Mongoose. In diesem Projekt haben wir nur ein Modell namens Message
. Dieses Nachrichtenmodell enthält nur Text
, createDate
, und Autor
User
, da wir ein Benutzerregistrierungs-/Anmeldesystem nicht vollständig implementieren werden. Es wird eine einfache Seite zur Bereitstellung von Spitznamen geben, und dieser Spitzname wird in einem Cookie gespeichert. Dies wird in der Nachricht
verwendet Modell als Text im Autor
Feld. Unten sehen Sie ein Beispiel für ein JSON-Modell:
{ text: "Hi, is there any Full Stack Developer here?" author: "john_the_full_stack", createDate: "2015.05.15" }
Um solche Dokumente zu erstellen, können Sie ein Modell implementieren, indem Sie die folgenden Mongoose-Funktionen verwenden:
var mongoose = require('mongoose') var Message = new mongoose.Schema({ author: String, message: String, createDate: { type: Date, default: Date.now } }); mongoose.model('Message', Message)
Importieren Sie einfach das Mongoose-Modul, definieren Sie Ihr Modell mit seinen Feldern und Feldattributen im JSON-Format und erstellen Sie ein Modell mit dem Namen Message
. Dieses Modell wird in die Seiten aufgenommen, die Sie verwenden möchten.
Vielleicht haben Sie eine Frage dazu, warum wir die Nachricht in der Datenbank speichern, wenn wir diese Nachricht bereits im selben Kanal an den Benutzer senden. Es stimmt, dass Sie Chatnachrichten nicht speichern müssen, aber ich wollte nur die Datenbankintegrationsschicht erklären. Wie auch immer, wir werden dieses Modell in unserem Projekt innerhalb der Controller verwenden. Controller?
2.2. Verantwortlicher
Wie ich bereits sagte, werden wir Express für den MVC-Teil verwenden. Und C
hier steht für Controller
. Für unsere Projekte gibt es nur zwei Endpunkte für Messaging. Einer von ihnen dient zum Laden der letzten Chat-Nachrichten, und der zweite dient zum Bearbeiten gesendeter Chat-Nachrichten, um sie in der Datenbank zu speichern und dann in den Kanal zu übertragen.
..... 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); }); }); .....
Der erste und der zweite Controller dienen nur dazu, statische HTML-Dateien für die Chat- und Anmeldeseiten bereitzustellen. Der dritte dient zur Bearbeitung der Post-Anfrage an /messages
Endpunkt zum Erstellen neuer Nachrichten. In diesem Controller wird zunächst der Request-Body in das Message-Model konvertiert und dieses Model dann mit der Mongoose-Funktion save
in der Datenbank gespeichert .
Ich werde nicht sehr viel auf Mongoose eingehen – Sie können sich die Dokumentation für weitere Details ansehen. Sie können eine Rückruffunktion für die Speicherfunktion bereitstellen, um zu prüfen, ob ein Problem vorliegt oder nicht. Wenn es erfolgreich ist, haben wir die letzten fünf Datensätze abgerufen, sortiert in absteigender Reihenfolge nach createDate
, und haben fünf Nachrichten an die Clients im Kanal gesendet.
Ok, wir haben MC
beendet . Wechseln wir zur Ansicht
Teil.
2.3. Anzeigen
Im Allgemeinen kann innerhalb von Express eine Template-Engine wie Jade, EJS, Handlebars usw. verwendet werden. Wir haben jedoch nur eine Seite, und das ist eine Chat-Nachricht, also werde ich diese statisch bereitstellen. Tatsächlich gibt es, wie ich oben sagte, zwei weitere Controller, um diese statische HTML-Seite bereitzustellen. Folgendes können Sie für die Bereitstellung einer statischen HTML-Seite sehen.
app.get('/chat', function(req, res){ res.sendFile(__dirname + '/index.html'); }); app.get('/login', function(req, res){ res.sendFile(__dirname + '/login.html'); });
Dieser Endpunkt stellt einfach index.html und login.html bereit, indem er res.sendFile
verwendet . Beide index.html und login.html befinden sich im selben Ordner wie server.js, weshalb wir __dirname
verwendet haben vor dem HTML-Dateinamen.
2.4. Frontend
Auf der Frontend-Seite habe ich Bootstrap verwendet und es ist nicht nötig zu erklären, wie ich das geschafft habe. Einfach, ich habe eine Funktion an ein Textfeld gebunden, und wann immer Sie die Enter drücken -Taste oder Senden klicken, wird die Nachricht an den Back-End-Dienst gesendet.
Diese Seite hat auch eine erforderliche js-Datei von Socket.IO, um den Kanal namens message
abzuhören . Das Socket.IO-Modul ist bereits im Back-End importiert, und wenn Sie dieses Modul auf der Serverseite verwenden, fügt es automatisch einen Endpunkt zum Bereitstellen der Socket.IO-js-Datei hinzu, aber wir verwenden den, der von cdn . Immer wenn eine neue Nachricht in diesem Kanal eingeht, wird sie automatisch erkannt und die Nachrichtenliste wird mit den letzten fünf Nachrichten aktualisiert.
<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>
Es gibt noch eine weitere Überprüfung im obigen Code:den Cookie-Teil. Wenn Sie keinen Spitznamen für den Chat ausgewählt haben, bedeutet dies, dass das Cookie für den Spitznamen nicht gesetzt ist und Sie automatisch zur Anmeldeseite weitergeleitet werden.
Wenn nicht, werden die letzten fünf Nachrichten durch einen einfachen Ajax-Aufruf an die /messages
abgerufen Endpunkt. Auf die gleiche Weise, wenn Sie auf Senden klicken oder drücken Sie die Eingabetaste Schlüssel wird die Textnachricht aus dem Textfeld und der Spitzname aus dem Cookie abgerufen, und diese Werte werden mit einer Post-Anforderung an den Server gesendet. Hier gibt es keine strenge Überprüfung des Spitznamens, weil ich mich auf den Echtzeitteil konzentrieren wollte, nicht auf den Teil der Benutzerauthentifizierung.
Wie Sie sehen können, ist die Gesamtstruktur des Projekts sehr einfach. Kommen wir zum Bereitstellungsteil. Wie ich bereits sagte, werden wir Modulus verwenden, eine der besten PaaS für die Bereitstellung, Skalierung und Überwachung Ihrer Anwendung in der Sprache Ihrer Wahl.
3. Bereitstellung
3.1. Voraussetzungen
Das erste, was mir in den Sinn kommt, ist, Ihnen zu zeigen, wie Sie bereitstellen, aber für eine erfolgreiche Bereitstellung benötigen wir eine funktionierende Datenbank. Sehen wir uns an, wie man eine Datenbank auf Modulus erstellt und dann die Bereitstellung durchführt.
Gehen Sie zum Modulus-Dashboard, nachdem Sie ein Konto erstellt haben. Klicken Sie auf Datenbanken Menü auf der linken Seite und klicken Sie auf Datenbank erstellen.
Füllen Sie die erforderlichen Felder im Popup-Formular wie unten aus.
Wenn Sie die erforderlichen Felder ausfüllen und auf Erstellen klicken Es erstellt eine MongoDB-Datenbank für Sie und Sie sehen Ihre Datenbank-URL auf dem Bildschirm. Wir verwenden MONGO-URI , Kopieren Sie also diesen URI.
In unserem Projekt wird der Mongo-URI aus der Umgebungsvariable MONGO_URI
abgerufen , und Sie müssen diese Umgebungsvariable im Dashboard festlegen. Gehen Sie zum Dashboard und klicken Sie auf Projekte Menü, wählen Sie Ihr Projekt in der Liste aus und klicken Sie auf Verwaltung im linken Menü. Auf dieser Seite sehen Sie den Abschnitt Umgebungsvariablen, wenn Sie die Seite nach unten scrollen, wie unten gezeigt.
Sie können Modulus auf zwei Arten bereitstellen:
- Hochladen der Projekt-ZIP-Datei über das Dashboard
- Bereitstellung über die Befehlszeile mit Modulus CLI
Ich werde mit der Befehlszeilenoption fortfahren, da die andere einfach zu bewerkstelligen ist. Installieren Sie zuerst Modulus CLI:
npm install -g modulus
Gehen Sie zu Ihrem Projektordner und führen Sie den folgenden Befehl aus, um sich bei Modulus anzumelden.
modulus login
Wenn Sie den obigen Befehl ausführen, werden Sie aufgefordert, einen Benutzernamen und ein Passwort einzugeben:
Wenn Sie mithilfe von GitHub ein Konto erstellt haben, können Sie --github
verwenden Option.
modulus login --github
Jetzt sind Sie bei Modulus angemeldet und es ist an der Zeit, ein Projekt zu erstellen. Verwenden Sie den folgenden Befehl, um ein Projekt zu erstellen:
modulus project create "Realtime Chat"
Wenn Sie diese Funktion ausführen, werden Sie nach der Laufzeit gefragt. Wählen Sie die erste Option, die Node.js ist, und zweitens werden Sie nach der Servogröße gefragt, und Sie können sie als Standard beibehalten.
Wir haben ein Projekt erstellt, und dieses Mal werden wir unser aktuelles Projekt für Modulus bereitstellen. Führen Sie den folgenden Befehl aus, um das aktuelle Projekt an den Echtzeit-Chat zu senden Projekt auf der Modulus-Seite.
modulus deploy
Es wird Ihr Projekt bereitstellen und Sie erhalten Ihre laufende Projekt-URL am Ende der erfolgreichen Bereitstellungsnachricht:
Realtime Chat running at realtime-chat-46792.onmodulus.net
Wie Sie sehen können, ist die Bereitstellung auf Modulus sehr einfach!
Modulus CLI verfügt über sehr hilfreiche Befehle, die Sie während Ihrer Projektbereitstellung oder zur Laufzeit verwenden können. Um zum Beispiel Protokolle Ihres laufenden Projekts zu taillen, können Sie modulus project logs tail
verwenden verwenden Sie zum Erstellen einer MongoDB-Datenbank modulus mongo create
, um eine Umgebungsvariable festzulegen, verwenden Sie modulus env set
usw. Sie können eine vollständige Liste der Befehle mithilfe der Modulus-Hilfe anzeigen.