In questo tutorial, ti mostrerò come implementare un'applicazione di chat in tempo reale con Node.js, Socket.IO e MongoDB, quindi distribuiremo questa applicazione su Modulus insieme.
Prima di tutto, lascia che ti mostri l'aspetto finale dell'applicazione che avremo alla fine dell'articolo.
Node.js sarà il nucleo dell'applicazione, con Express come MVC, MongoDB per il database e Socket.IO per la comunicazione in tempo reale. Al termine, distribuiremo la nostra applicazione su Modulus. La parte MongoDB esiste effettivamente all'interno di Modulus.
1. Scenario
- John vuole usare la nostra applicazione e la apre nel browser.
- Nella prima pagina, seleziona un nickname da usare durante la chat e accede alla chat.
- Nell'area di testo scrive qualcosa e preme Invio.
- Il testo viene inviato a un servizio RESTful (Express) e questo testo viene scritto su MongoDB.
- Prima di scrivere in MongoDB, lo stesso testo verrà trasmesso agli utenti che sono attualmente collegati all'app di chat.
Come puoi vedere, questa è un'app molto semplice, ma copre quasi tutto per un'applicazione web. Non esiste un sistema di canali in questa applicazione, ma puoi eseguire il fork del codice sorgente e implementare il modulo del canale per esercitarti.
2. Progettazione del progetto da zero
Proverò a spiegare prima i piccoli pezzi del progetto e a combinarli alla fine. Inizierò dal back-end al front-end. Quindi, iniziamo con gli oggetti di dominio (modelli MongoDB).
2.1. Modello
Per l'astrazione del database, useremo Mongoose. In questo progetto, abbiamo un solo modello chiamato Message
. Questo modello di messaggio contiene solo text
, createDate
, e author
User
, perché non implementeremo completamente un sistema di registrazione/accesso degli utenti. Ci sarà una semplice pagina che fornisce il nickname e questo nickname verrà salvato in un cookie. Questo verrà utilizzato nel Message
modello come testo nel author
campo. Puoi vedere un modello JSON di esempio di seguito:
{ text: "Hi, is there any Full Stack Developer here?" author: "john_the_full_stack", createDate: "2015.05.15" }
Per creare documenti come questo, puoi implementare un modello utilizzando le seguenti funzioni Mongoose:
var mongoose = require('mongoose') var Message = new mongoose.Schema({ author: String, message: String, createDate: { type: Date, default: Date.now } }); mongoose.model('Message', Message)
Importa semplicemente il modulo Mongoose, definisci il tuo modello con i suoi campi e attributi di campo in formato JSON e crea un modello con il nome Message
. Questo modello verrà incluso nelle pagine che desideri utilizzare.
Forse hai una domanda sul motivo per cui stiamo archiviando il messaggio nel database, quando abbiamo già trasmesso questo messaggio all'utente nello stesso canale. È vero che non devi memorizzare i messaggi di chat, ma volevo solo spiegare il livello di integrazione del database. Ad ogni modo, utilizzeremo questo modello nel nostro progetto all'interno dei controller. Controllori?
2.2. Titolare
Come ho detto prima, useremo Express per la parte MVC. E C
qui sta per il Controller
. Per i nostri progetti, ci saranno solo due endpoint per la messaggistica. Uno di questi serve per caricare i messaggi di chat recenti e il secondo per gestire i messaggi di chat inviati da archiviare nel database e quindi trasmettere nel canale.
..... 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); }); }); .....
Il primo e il secondo controller servono solo per servire file HTML statici per le pagine di chat e di accesso. Il terzo serve per gestire la richiesta di posta al /messages
endpoint per la creazione di nuovi messaggi. In questo controller, prima di tutto il corpo della richiesta viene convertito nel modello del messaggio, quindi questo modello viene salvato nel database utilizzando la funzione Mongoose save
.
Non mi immergerò molto in Mongoose:puoi dare un'occhiata alla documentazione per ulteriori dettagli. È possibile fornire una funzione di callback per la funzione di salvataggio per verificare se ci sono problemi o meno. Se ha esito positivo, abbiamo recuperato gli ultimi cinque record ordinati in ordine decrescente per createDate
e hanno trasmesso cinque messaggi ai client nel canale.
Ok, abbiamo finito MC
. Passiamo alla View
parte.
2.3. Visualizza
In generale, all'interno di Express è possibile utilizzare un motore di modelli come Jade, EJS, Handlebars, ecc. Tuttavia, abbiamo solo una pagina, e questo è un messaggio di chat, quindi lo servirò in modo statico. In realtà, come ho detto sopra, ci sono altri due controller per servire questa pagina HTML statica. Puoi vedere quanto segue per servire una pagina HTML statica.
app.get('/chat', function(req, res){ res.sendFile(__dirname + '/index.html'); }); app.get('/login', function(req, res){ res.sendFile(__dirname + '/login.html'); });
Questo endpoint serve semplicemente index.html e login.html utilizzando res.sendFile
. Entrambi index.html e login.html si trovano nella stessa cartella di server.js, motivo per cui abbiamo usato __dirname
prima del nome del file HTML.
2.4. Front-end
Nella pagina front-end, ho usato Bootstrap e non c'è bisogno di spiegare come sono riuscito a farlo. Semplicemente, ho associato una funzione a una casella di testo e ogni volta che premi il Invio chiave o Invia pulsante, il messaggio verrà inviato al servizio di back-end.
Questa pagina ha anche un file js richiesto di Socket.IO per ascoltare il canale chiamato message
. Il modulo Socket.IO è già importato nel back-end e, quando utilizzi questo modulo sul lato server, aggiunge automaticamente un endpoint per servire il file js Socket.IO, ma utilizziamo quello servito da cdn <script src="//cdn.socket.io/socket.io-1.3.5.js"></script>
. Ogni volta che un nuovo messaggio arriva su questo canale, verrà rilevato automaticamente e l'elenco dei messaggi verrà aggiornato con gli ultimi cinque messaggi.
<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>
C'è un altro controllo nel codice sopra:la parte del cookie. Se non hai scelto alcun nickname per la chat, significa che il cookie non è impostato per il nickname e verrai reindirizzato automaticamente alla pagina di accesso.
In caso contrario, gli ultimi cinque messaggi verranno recuperati tramite una semplice chiamata Ajax a /messages
punto finale. Allo stesso modo, ogni volta che fai clic su Invia o premi il pulsante Invio chiave, il messaggio di testo verrà recuperato dalla casella di testo e il nickname verrà recuperato dal cookie e quei valori verranno inviati al server con una richiesta di post. Non c'è un controllo rigoroso per il nickname qui, perché volevo concentrarmi sulla parte in tempo reale, non sulla parte di autenticazione dell'utente.
Come puoi vedere, la struttura complessiva del progetto è molto semplice. Veniamo alla parte di distribuzione. Come ho detto in precedenza, utilizzeremo Modulus, uno dei migliori PaaS per distribuire, ridimensionare e monitorare la tua applicazione nella lingua di tua scelta.
3. Distribuzione
3.1. Prerequisiti
La prima cosa che mi viene in mente è mostrarti come eseguire la distribuzione, ma per una distribuzione di successo, abbiamo bisogno di un database funzionante. Diamo un'occhiata a come creare un database su Modulus e quindi eseguire la distribuzione.
Vai alla dashboard di Modulus dopo aver creato un account. Fai clic su Database menu a sinistra e fai clic su Crea database.
Compila i campi richiesti nel modulo popup come di seguito.
Quando compili i campi richiesti e fai clic su Crea, creerà un database MongoDB per te e vedrai l'URL del tuo database sullo schermo. Useremo MONGO URI , quindi copia quell'URI.
Nel nostro progetto, l'URI Mongo viene recuperato dalla variabile di ambiente MONGO_URI
e devi impostare quella variabile di ambiente nel dashboard. Vai alla dashboard, fai clic su Progetti menu, seleziona il tuo progetto nell'elenco e fai clic su Amministrazione nel menu a sinistra. In questa pagina vedrai la sezione delle variabili d'ambiente quando scorri la pagina verso il basso, come mostrato di seguito.
Puoi eseguire il deployment su Modulus in due modi:
- caricare il file ZIP del progetto utilizzando la dashboard
- distribuzione dalla riga di comando utilizzando Modulus CLI
Continuerò con l'opzione della riga di comando, perché l'altra è facile da fare. Prima di tutto, installa Modulus CLI:
npm install -g modulus
Vai alla cartella del tuo progetto ed esegui il seguente comando per accedere a Modulus.
modulus login
Quando esegui il comando precedente, ti verrà chiesto di inserire un nome utente e una password:
Se hai creato un account utilizzando GitHub, puoi utilizzare il --github
opzione.
modulus login --github
Ora sei connesso a Modulus ed è il momento di creare un progetto. Utilizzare il comando seguente per creare un progetto:
modulus project create "Realtime Chat"
Quando esegui questa funzione, ti verrà chiesto il runtime. Seleziona la prima opzione, che è Node.js, e la seconda ti verrà chiesta la dimensione del servo e potrai mantenerla come predefinita.
Abbiamo creato un progetto e questa volta implementeremo il nostro progetto attuale su Modulus. Esegui il comando seguente per inviare il progetto corrente alla Chat in tempo reale progetto lato modulo.
modulus deploy
Distribuirà il tuo progetto e otterrai l'URL del tuo progetto in esecuzione alla fine del messaggio di distribuzione riuscita:
Realtime Chat running at realtime-chat-46792.onmodulus.net
Come puoi vedere, l'implementazione su Modulus è molto semplice!
Modulus CLI dispone di comandi molto utili da utilizzare durante la distribuzione del progetto o in fase di esecuzione. Ad esempio, per eseguire la coda dei log del tuo progetto in esecuzione, puoi utilizzare modulus project logs tail
, per creare un database MongoDB usa modulus mongo create <db-name>
, per impostare una variabile di ambiente utilizzare modulus env set <key> <value>
, ecc. È possibile visualizzare un elenco completo di comandi utilizzando la guida di Modulus.