Node: terrore dallo spazio profondo, prima puntata

Node é la dimostrazione lampante di come gli aspetti nuovi dell’ esistenza, quelli che ci fanno uscire dalla nostra zona di confort, siano perfetti per spaventarci ed intimorirci con i suoi inediti comandi da common line interface o CLI o anche CMD, l’antica finestra dos che usavamo tanti anni fa per digitare comandi manuali sulle directory. Terrore dallo spazio profondo (Invasion of the Body Snatchers) è un film del 1978 diretto da Philip Kaufman, remake del classico del 1956 L’invasione degli ultracorpi, tratto dall’omonimo romanzo del 1954 dello scrittore Jack Finney. ll fatto è che Node con il suo javascript lato server non solo ha portato un vento innovativo rispetto ai vecchi clichè, ma anche tante angosce esistenziali dal momento che ci costringe a programmare in un modo del tutto nuovo, decisamente dinamico. Il software installabile da https://nodejs.org/it/ . Abbiamo già detto che il framework lavora in backend e che rappresenta un ambiente di esecuzione asincrono? Supporta nativamente i file json, ha un manager che si preoccupa di installare pacchetti, non è difficile da imparare come Angular. Come al solito per lavorare con node servirà un editor a piacere tipo il bellissimo Visual Studio Code: https://code.visualstudio.com/ . Molti programmatori al top usano WebStorm ricco di funzionalità ma possiamo dunque definire le scelte personali mode? Soprattutto se sono a pagamento? Anche brackets non é male, insomma c’è l’imbarazzo della scelta. Ora tocca a NPM il gestore dei moduli da installare: https://www.npmjs.com/; a questo punto sappiamo che dobbiamo prima entrare nella cartella di lavoro, magari sul desktop per semplicità, poi una volta puntata dobbiamo inizializzare il progetto con il comando npm init che crea il famoso package.json, questo come fase di preparazione dove abbiamo nella root l’indicazione del file da lanciare o rendere eseguibile (index.js) e tutte le altre dipendenze scarne al momento di un progetto vuoto ancora da riempire con moduli come express per esempio che si occupa della gestione server. Questo nel caso che non si vogliano modificare le impostazioni di default altrimenti posso modificare il mio entry level e il nome del file a inizio processo. Con npm install express posso installare il mio modulo funzionalità per la gestione HTTP e delle richieste post e get e asincrone. Con npm install creo le dipendenze, installo le dipendenze nella cartella node_modules locale. In modalità globale, ovvero, con -g o –global aggiunti al comando, installa il contesto del pacchetto corrente, ovvero la directory di lavoro corrente, come pacchetto globale. Per impostazione predefinita, npm install installa tutti i moduli elencati come dipendenze nel pacchetto json. Per disinstallare i moduli uso npm unistall express per esempio. Analizziamo ora questo semplice script:

const http = require(‘http’);

function checkTime(i) {
if (i < 10)
i = “0” + i;

return i;
}

http.createServer(function(req, res){

var today = new Date();
var h = today.getHours();
var m = today.getMinutes();
var s = today.getSeconds();

// Adds a zero in front of numbers < 10
m = checkTime(m);
s = checkTime(s);

res.end(h+ “:” + m + “:” + s);

}).listen(8080);

essendo il modulo http simile a una rete che smista chiamate e risposte, request e response, gli esperimenti che potremmo fare riguardano proprio questo ambito, con risposte o schiaffi alla palla tennistica che avvengono simultaneamente (io chiedo e tu mi rispondi senza fare altro ma se c’è un processo in corso viene penalizzato con un abbondanza di risorse) o palle-metafora che vengono gestite con intervalli di tempo asincrono a seconda dei compiti da svolgere a sistema. La funzione all’ inizio richiama un modulo che gestisce le chiamate server, poi definisce una funzione che prende in ingresso un argomento che non fa altro che controllare lo stato della pagina e aggiornarla ogni dieci secondi. Sotto abbiamo una semplice funzione di chiamata server in cui diciamo anche di rispondere e di aggiornare lo stato dei minuti e dei secondi al tempo che abbiamo definito dalla funzione checkTime. Questo potremmo considerarlo un esempio funzionale di chiamata asincrona elementare gestita solo da HTTP module senza l’intervento di express. Quindi alla domanda ma siamo in grado di mettere in piedi server artigianali dell’ era primordiale senza installare moduli esterni ma richiamando le risorse già integrate in node la risposta é sì! Andiamo oltre e analizziamo un caso ancora primordiale di richiesta ma leggermente più complicata rispetto al solo metodo http. Qui si tratta di materializzare una pagina che però ha delle risorse costruite dinamicamente in un ciclo che le localizza e che avrà due stati: se queste risorse non vengono viste allora siamo nel blocco errore dove compariranno i messaggi tematici, altrimenti significherà che é andato tutto bene e che la request avra avuto una sua response con una serie di goie sullo stato 200 (success!) di conferma ricezione preliminare al rendering della pagina index.html:

const http = require(‘http’);
const fs = require(‘fs’);
const url = require(‘url’);
const path = require(‘path’);

http.createServer((req, res) => {

if (req.url == ‘/’) {
req.url = ‘/index.html’;
}

var urlParts = url.parse(req.url);

fs.readFile(urlParts.pathname.substr(1), (err, data) => {

if (err) {

res.writeHead(404);
res.end();
return;

}

var headers = null;
var fileExtension = path.extname(urlParts.pathname.substr(1));

switch (fileExtension) {

case ‘.html’:
headers = {‘Content-Type’: ‘text/html’};
break;

case ‘.css’:
headers = {‘Content-Type’: ‘text/css’};
break;

case ‘.js’:
headers = {‘Content-Type’: ‘text/javascript’};
break;

case ‘.jpg’:
headers = {‘Content-Type’: ‘image/jpeg’};
break;

default:
headers = {‘Content-Type’: ‘application/octet-stream’};

}

res.writeHead(200, headers);
res.end(data);

});

}).listen(8080);

da notare lo script come controlla le richieste in base ai criteri di autorizzazione Content-Type: identifica il tipo di contenuto e decide quali moduli possono contribuire al risultato a video della nostra chiamata asincrona; andando sulla porta 8080 di default della localhost sarà il seguente:

Se volessi creare un semplice collegamento sincrono come faccio? Analizziamo questo file:

const http = require(‘http’);
const fs = require(‘fs’);

http.createServer( (req, res) => {

var data = fs.readFileSync(“../index.html”);
res.end(data);

}).listen(8080);

Lo script integra con il metodo require i moduli http e fs (file system) per poter funzionare, poi mette in moto una funzione abbreviata arrow secondo la nuova sintassi javascript che fa una richiesta per avere una una risorsa e ottiene una risposta infine con la proprietà end del metodo res. E se volessi ottenere una risposta asincrona come faccio? Analizziamo il seguente file script:

const http = require(‘http’);
const fs = require(‘fs’);

http.createServer( (req, res) => {

fs.readFile(‘../index.html’, (err, data) => {

if (err) throw err;

res.end(data);

});

}).listen(8080);

mentre il file di prima si limitava a leggere una risorsa e a restituirla con l’oggetto fs importato, qui la funzione ARROW che si appoggia su fs.readFile che di default è asyncrono se non specificato, mette in scena una istruzione condizionale con un controllo d’errore che prima non c’era, la risorsa viene letta e restituita nel suo contenuto. Sui metodi e le proprietà dell’ oggetto HTTP di NODE si rimanda alla documentazione ufficiale all’ indirizzo: https://nodejs.org/api/http.html . A questo punto facciamo entrare il CR7 della situazione, analizziamo il seguente file server.js che carica il contenuto di una risorsa previa interrogazione:

const http = require(‘http’);
const fs = require(‘fs’);
const url = require(‘url’);
const path = require(‘path’);
const qs = require(‘querystring’);

var doc = null;

http.createServer((req, res) => {

if (req.method == ‘GET’) {

if (req.url == ‘/’) {

req.url = ‘/index.html’;

} else if (req.url == ‘/load’) {

if (doc == null) {

res.writeHead(200);
res.end();

} else {

res.writeHead(200, {‘Content-Type’: ‘application/json’});
res.end(JSON.stringify(doc));

}

}

var urlParts = url.parse(req.url);

fs.readFile(urlParts.pathname.substr(1), (err, data) => {

if (err) {

res.writeHead(404);
res.end();
return;

}

var headers = null;
var fileExtension = path.extname(urlParts.pathname.substr(1));

switch (fileExtension) {

case ‘.html’:
headers = {‘Content-Type’: ‘text/html’};
break;

case ‘.css’:
headers = {‘Content-Type’: ‘text/css’};
break;

case ‘.js’:
headers = {‘Content-Type’: ‘text/javascript’};
break;

case ‘.jpg’:
headers = {‘Content-Type’: ‘image/jpeg’};
break;

default:
headers = {‘Content-Type’: ‘application/octet-stream’};

}

res.writeHead(200, headers);
res.end(data);

});

} else if (req.method == ‘POST’) {

var body = ”;

req.on(‘data’, (data) => {

body += data;

});

req.on(‘end’, () => {

var postData = qs.parse(body);

if (Object.prototype.hasOwnProperty.call(postData, ‘title’) && Object.prototype.hasOwnProperty.call(postData, ‘body’)) {

doc = postData;
res.writeHead(200);
res.end();

} else {

res.writeHead(400);
res.end();

}

});

}

}).listen(8080);

In questo script vengono contemplate diverse richieste dalla tipologia diversa, se è una richiesta GET fai qualcosa, se è una richiesta di tipo POST, fai qualcos’ altro, se utilizzi il metodo LOAD comportati in maniera diversa: Nel file sono presenti metodi per convertire il contenuto da js a json e poi metodi per parserizzare la restituzione. Il file è di supporto a una pagina html appoggiata a sua volta a una cartella script che salva il contenuto del documento e lo invia con il metodo post alla pagina localhost:8080, la richiesta è gestita a seconda della tipologia dalla pagina server.js in chiave dinamica. Possiamo definirla una applicazione completa per scrittori perchè il testo aggiunto viene salvato grazie ai metodi offerti dalle librerie :

require(‘http’);
require(‘fs’);
require(‘url’);
require(‘path’);
require(‘querystring’);

La domanda sorge spontanea se volessi pubblicare tutto questo su server tradizionale tipo Aruba lo posso fare? Si sui servizi dedicati immaginiamo ma in realtà esistono servizi specifici che fanno funzionare gli script NODE. Per una vissione completa rimandiamo ad articoli presenti in rete del tipo https://trovalost.it/hostare-progetto-node-js-e-quali-hosting-usare/ ; siamo arrivati a un punto critico della navigazione node a questo punto non ci resta che parlare di EXPRESS e del suo labirinto! Per installare un modulo sappiamo di dover usare il comando npm install express puntando alla cartella di progetto. Fatto? Ok adesso mettiamo anche Helmet con il comando npm install helmet. Helmet ti aiuta a proteggere le tue app Express impostando varie intestazioni HTTP. Non è un proiettile d’argento, ma può aiutare! Ok! Cosa deve fare la nostra APP usando Express? La stessa cosa che vediamo fare dal secondo file postato e quindi vediamo le differenze sostanziali tra il qui presente Express attivo in una comparazione del file server.js, da notare come i metodi usati conferiscano una sintessa agile e snella rispetto al primo caso, non solo ma adesso la console risponde celermente con dei messaggi di avvenuta esecuzione per la nostra localhost:8080. Da notare anche l’espressione app.use(helmet()) , un modulo che raccoglie 12 funzioni più piccole che impostano le intestazioni di risposta HTTP:

const express = require(‘express’);
const helmet = require(‘helmet’);

const app = express();
app.use(helmet());

app.use( (req, res, next) => {

console.log(“Request made at time: “, Date.now());

next();

});

app.get(‘/’, (req, res) => {

res.sendFile(__dirname + ‘/index.html’);

});

app.use(‘/assets’, (req, res, next) => {

console.log(“Serving a file from the assets directory”);

next();

}, express.static(‘assets’));

app.listen(8080);

 

il risultato è lo stesso del secondo esempio, la pagina viene caricata, ma le dinamiche che si nascondono dietro il sipario sono state enormemente semplificate e migliorate in termini di sicurezza

 

 

 

 

CONSLUSIONI: una volta di come si entra nella forma mentis di NODE con le sue installazioni di moduli e le sue dipendenze, con le sue iniziazioni per creare il file packages.json, con le sue gerarchie e il modo di lanciare gli eseguibili e modificare anche in entry level le chiamate da CLI, con le sue visualizzazioni su localhost porta 8080 di default, il terrore iniziale diventa meno incisivo e il tutto si affievolisce. L’unico modo per entrare nel vivo del funzionamento di NODE è quello di sperimentare il codice.

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo di WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Google photo

Stai commentando usando il tuo account Google. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...

%d blogger hanno fatto clic su Mi Piace per questo: