Possiamo ora passare ad una prima semplicissima applicazione per Node.js, prendendo come punto di partenza del nostro percorso didattico, la creazione di un semplice webserver.
Un webserver รจ essenzialmente un programma che attende delle richieste mettendosi, per cosรฌ dire, in "ascolto" su determinate porte, e che fornisce al client, a seconda dei parametri della richiesta, una risposta adeguata.
Grazie ai moduli di Node e alle loro API, predisporre un server di base รจ molto semplice. Proponiamo questo codice che poi andremo ad analizzare in dettaglio:
var http = require("http");
function elabora_richiesta(richiesta, risposta) {
var testo = 'Risposta dal server\n';
var lunghezza_contenuto = testo.length;
risposta.writeHead(200, {
'Content-Length': lunghezza_contenuto,
'Content-Type': 'text/plain'
});
risposta.end(testo);
}
var s = http.createServer(elabora_richiesta);
s.listen(8080);
Per eseguirlo possiamo salvarlo col nome server.js, e lanciare il comando
node server.js
Lโesecuzione rimarrร attiva fino a quando non verrร interrotta con il comando CTRL+C.
Il funzionamento del webserver
Alla prima riga includiamo il modulo http tramite il comando require, e rendiamo disponibili le sue API tramite la variabile http. I moduli sono raggruppamenti di funzioni connesse fra loro, come ad esempio quelle relative alla gestione del protocollo http, oppure alla lettura e scrittura dei file. Diversi moduli sono inclusi nativamente con Node, e vedremo โ nelle prossime lezioni โ in che modo possiamo aggiungerne degli altri tramite il noto gestore di pacchetti npm, oppure come crearli autonomamente.
Il metodo createServer, utilizzato alla penultima riga, crea il webserver assegnandolo alla variabile "s", mentre il metodo listen, applicato a questโultima, mette in ascolto il server alla porta 8080. Questo significa che potremo ottenere una risposta o tramite il browser, inserendo come indirizzo http://localhost:8080/, oppure tramite terminale con il comando cUrl:
curl -i http://localhost:8080
Lโopzione -i richiede che vengano visualizzate le intestazioni.
Ecco la risposta che otterremo:
HTTP/1.1 200 OK
Content-Length: 21
Content-Type: text/plain
Date: Sat, 23 Apr 2016 17:00:34 GMT
Connection: keep-alive
Risposta dal server
Come viene ottenuto questo risultato? Una volta ricevuta la richiesta il webserver richiamerร la funzione elabora_richiesta che abbiamo definito, e che prevede come parametri la richiesta effettuata e la risposta da inviare.
Il metodo writeHead comincia a scrivere le intestazioni, e il suo funzionamento รจ molto intuitivo: il primo parametro numerico รจ il codice di risposta (in questo caso il 200 di OK; possiamo trovare a questa pagina un elenco completo dei codici di risposta: ), mentre il secondo parametro sono le intestazioni (header) vere e proprie (in questa pagina possiamo trovare la lista completa ) passate come oggetto JavaScript. La lunghezza del testo col quale risponderemo alla richiesta viene calcolato col metodo length, un metodo nativo JavaScript applicabile alle stringhe. La lunghezza viene quindi passata allโintestazione Content-Length.
Una volta terminata lโimpostazione delle intestazioni il metodo end, a cui abbiamo passato il corpo del messaggio, comunica al server che la risposta รจ stata completamente predisposta, e che possono essere inviate le intestazioni e il messaggio stesso.
Ottenre altre informazioni ed espandere le funzionalitร
In poche righe abbiamo creato una struttura di base che espanderemo con nuove funzioni nel corso della guida (ad esempio per inviare come risposta documenti html, o altri tipi di file fra i quali immagini, fogli di stile e script, e anche per ricevere ed elaborare dati via POST), tenendo sempre conto della necessitร di programmare il nostro server in modo asincrono. Node rende il compito piuttosto semplice, fornendoci anche un facile accesso a tutti i dati che vengono inviati nella richiesta. Proviamo ad esempio questa semplice variante:
var http = require("http");
function elabora_richiesta(richiesta, risposta) {
var testo = richiesta.method + " " + richiesta.url + "\n";
var lunghezza_contenuto = testo.length;
risposta.writeHead(200, {
'Content-Length': lunghezza_contenuto,
'Content-Type': 'text/plain'
});
risposta.end(testo);
}
var s = http.createServer(elabora_richiesta);
s.listen(8080);
Col comando
curl http://localhost:8080/index.html
otterrenmo come risposta
GET /index.html
Ottenendo quindi il metodo utilizzato nella chiamata e il relativo URL tramite le proprietร method e url associati al parametro della richiesta. Vale a dire i dati fondamentali per predisporre unโapplicazione lato server che gestisca adeguatamente le risposte ai client.
La modularitร di Node facilita la costruzione delle nostre applicazioni, rendendo disponibile API semplici e potenti in moltissimi ambiti, a partire da quelli piรน tradizionali del server-side.
Nelle prossime lezioni da un lato ci occuperemo di espandere le funzionalitร della struttura che abbiamo abbozzato tramite le programmazione asincrona, e dallโaltro mostreremo come ottenere le basi di tecnologie anche completamete diverse sia attraverso lโottimo package manager npm, sia creando autonomamente dei moduli personalizzati.