Node.js
Transcript
Node.js
Dott.Ing.Ivan Ferrazzi Node.js Introduzione alla programmazione Dott. Ing. Ivan Ferrazzi V1.0 del 05/11/2012 1/15 Dott.Ing.Ivan Ferrazzi Copyright ©2012 Dott.Ing. Ivan Ferrazzi Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. 2/15 Dott.Ing.Ivan Ferrazzi Indice generale INTRODUZIONE....................................................................................................4 CONCETTI BASE...................................................................................................6 Gli oggetti........................................................................................................6 Gli eventi.........................................................................................................8 Le finestre di dialogo.....................................................................................10 Le finestre......................................................................................................12 Concatenare diversi elementi........................................................................13 I FORM...............................................................................................................15 Interagire con i componenti di un modulo FORM...........................................15 VARIABILI ED OGGETTI......................................................................................18 Operazioni con variabili.................................................................................18 Le stringhe oggetto String.............................................................................19 Oggetto Date.................................................................................................22 Oggetto Image...............................................................................................23 Oggetto frame e parent.................................................................................24 Gli array.........................................................................................................25 LE FUNZIONI......................................................................................................27 Concetto base................................................................................................27 Variabili locali e globali..................................................................................29 IL RICHIAMO DI OGGETTI...................................................................................30 Come utilizzare getElementById().................................................................30 COMANDI CONDIZIONALI E CICLI.......................................................................32 Comando condizionale if...else......................................................................32 Il comando condizionale switch.....................................................................33 Il ciclo for.......................................................................................................34 Il ciclo while...................................................................................................35 3/15 Dott.Ing.Ivan Ferrazzi INTRODUZIONE Concetto Node.js è un framework che ci permette di creare applicativi server-side sfruttano il linguaggio Javascript normalmente utilizzato per la realizzazione di codice client-side. Il sistema si basa su Javascript Engine V8 della Google ed è disponibile per le maggiori piattaforme. Node.js sfrutta la programmazione ad eventi, ossia la programmazione basata sul modello “event-driven”. Il programma rimane in attesa di specifici eventi ai quali il sistema reagisce in determinata maniera. Il tutto avviene in maniera asincrona per garantire una maggiore efficienza di elaborazione. Installazione Per installare il pacchetto node.js scarichiamo l'ultima versione in formato .tar.gz e lo installiamo da sorgente utilizzando la classica procedura: # # # # # tar xzf nodejs-vxx.tar.gz cd nodejs-vxx ./configure make make install Per verificare che l'installazione sia andata a buon fine digitiamo da terminale # node 4/15 Dott.Ing.Ivan Ferrazzi > console.log(1) 1 5/15 Dott.Ing.Ivan Ferrazzi IL LINGUAGGIO Il mio primo programma nodejs Creiamo ora un piccolo programma nodejs che manda la stringa “Buongiorno a tutti!” direttamente sullo standard output della console. Apriamo un editor e scriviamo il seguente codice: console.log(“Buongiorno a tutti!”); Salviamo ora il file con il nome buongiorno.js e mandiamo in esecuzione il programma da terminale come segue: $ node buongiorno.js Buongiorno a tutti! In questo caso utilizziamo l'oggetto console che metta a disposizione il metodo log() con il quale si può mandare una stringa sullo standard output della console stessa. I moduli di nodejs Il sistema base di nodejs mette a disposizione un numero limitato di metodi utilizzabili direttamente all'interno del codice. Per aggiungere nuove funzionalità dobbiamo integrare dei moduli dove ogni modulo aggiunge una classe o singoli metodi utilizzabili all'interno del codice. I singoli moduli vengono importati con il metodo di base require come 6/15 Dott.Ing.Ivan Ferrazzi segue: var url = require('url'); Normalmente si cerca di utilizzare come nome della variabile lo stesso del modulo importato. In questo caso viene creato l'oggetto dal modulo url richiamabile dall'omonima variabile di oggetto url. Andiamo ad analizzare alcuni dei moduli messi a disposizione da nodejs. Il modulo globals Questo modulo non viene importato perché già presente all'interno del sistema base. Ecco perché è possibile utilizzare alcuni oggetti come console per interagire con lo standard output ed output degli errori, oppure variabili come __filename che fornisce a livello di runtime il nome del file avviato e __dirname che ne fornisce la cartella corrente. Il modulo http Questo modulo contiene la classe http.Server che permette di avviare un server web con una serie di oggetti in grado di ottimizzare questa funzione. Il modulo url Questo modulo permette di creare, trasformare e manipolare gli url sotto forma di oggetti o stringhe. Cerchiamo di capire il funzionamento di questo modulo partendo dal seguente esempio: http://user:[email protected]:8080/p/a/t/h?query=string#hash Le singole parti dell'url vengono definite come segue: href protocol host auth hostname port pathname search path query hash identifica l'intera url identifica il protocollo usato, ossia http: identifica il nome di dominio con il numero della porta, ossia host.com:8080 identifica la parte utilizzata per l'autenticazione, ossia user:pass identifica solamente il dominio, ossia host.com identifica solo la porta utilizzata, ossia 8080 identifica il percorso alla risorsa, ossia /p/a/t/h identifica la parte relativa alla richiesta inviata alla relativa pagina, ossia ?query=string identifica l'insieme tra pathname e search identifica solamente l'elenco delle informazioni GET passate alla relativa pagina, ossia query=string identifica la parte di ancoraggio all'interno della pagina, ossia #hash 7/15 Dott.Ing.Ivan Ferrazzi Verranno ora una serie di metodi che si hanno a disposizione con l'utilizzo di questo modulo: url.parse(urlStr, [parseQueryString], [slashesDenoteHost]) Questo metodo converte una stringa in un oggetto. Se parseQueryString è true la query string viene elaborata dal modulo querystring. Se settiamo come true il terzo parametro allora //foo/bar viene suddiviso in host (//foo) e pathname (/bar), piuttosto che pathname (//foo/bar). var url = require('url'); var obj = url.parse('http://www.google.it/index.html?cerca=12'); console.log(obj); restituisce il seguente risultato { protocol: 'http:', slashes: true, host: 'www.google.it', hostname: 'www.google.it', href: 'http://www.google.it/index.html?cerca=12', search: '?cerca=12', query: 'cerca=12', pathname: '/index.html', path: '/index.html?cerca=12' } url.format(urlObj) Recupera le informazioni dell'oggetto urlObj e ne crea una relativa stringa url. Il modulo path Questo modulo permette di gestire i percorsi reali del sistema operativo. path.join([path1],[path2],[...]) Questa funzione concatena una serie di percorsi restituendo il percorso effettivo: path.join('/foo', 'bar', 'baz/asdf', 'quux', '..') restituisce la seguente stringa: '/foo/bar/baz/asdf' path.resolve([from ...], to) Questa funzione esegue una serie di cd e restituisce infine la personal work directory. 8/15 Dott.Ing.Ivan Ferrazzi path.resolve('/foo/bar', '../baz') restituisce '/foo/baz' path.relative(from, to) Restituisce il percorso relativo per arrivare al percorso to partendo da from. path.relative('./orandea/test/aaa', './orandea/impl/bbb') restituisce '../../impl/bbb' path.dirname(p) Questa funzione restituisce il precorso al file. path.dirname('/foo/bar/baz/asdf/quux') restituisce '/foo/bar/baz/asdf' path.basename(p, [ext]) Possiamo utilizzare questa funzione per recuperare il solo nome del file senza il percorso come segue: path.basename('/foo/bar/baz/asdf/quux.html') restituisce 'quux.html' path.basename('/foo/bar/baz/asdf/quux.html', '.html') restituisce 'quux' path.extname(p) Questa funzione restituisce l'estensione del file fornito. 'index.html' restituisce '.html', 'index.' restituisce '.', mentre 'index' restituisce una stringa vuoto. 9/15 Dott.Ing.Ivan Ferrazzi Il modulo fs (file system) Questo modulo, in combinazione con il modulo path, permette di gestire al meglio le operazioni sul file system come copiare, rinominare, spostare, leggere e/o scrivere nei file. Vediamo alcune delle funzioni più importanti. Il modulo contiene dei metodi con elaborazione sincrona ed altri con elaborazione asincrona. Vediamo qui di seguito alcuni dei metodi asincroni: fs.rename(oldPath, newPath, [callback]) Questa funzione permette di rinominare un file come segue: fs.rename('/tmp/hello', '/tmp/world', function (err) { if (err) throw err; console.log('renamed complete'); }); La funzione di callback recupera lo stato dell'esito della funzione stessa. fs.unlink(path, [callback]) La funzione unlink permette di cancellare un file identificato da path: fs.unlink('/tmp/hello', function (err) { if (err) throw err; console.log('successfully deleted /tmp/hello'); }); fs.mkdir(path, [mode], [callback]) Questa funzione crea la cartella path. Il parametro mode è settato a 0777. fs.readdir(path, [callback]) Con questa funzione possiamo leggere il contenuto di una cartelle. La funzione di callback si aspetta infatti due parametri err e files dove files è un array che contiene i file tranne '.' e '..' . fs.readFile(filename, [encoding], [callback]) Questa funzione legge il contenuto di un file come segue: fs.readFile('/etc/passwd', 'utf-8', function (err, data) { if (err) throw err; console.log(data); }); Nella funzione di callback il parametro data ha come valore il contenuto del file. fs.writeFile(filename, data, [encoding], [callback]) Questa funzione prende la stringa data e la salva all'interno del file indicato da filename. Vediamo un semplice esempio: 10/15 Dott.Ing.Ivan Ferrazzi fs.writeFile('message.txt', 'Hello Node', function (err) { if (err) throw err; console.log('It\'s saved!'); }); fs.appendFile(filename, data, encoding='utf-8', [callback]) Per aggiungere la stringa contenuta in data nel file filename usiamo la funzione come segue: fs.appendFile('message.txt', 'data to append', function (err) { if (err) throw err; console.log('The "data to append" was appended to file!'); }); fs.stat(path, [callback]) Questa funzione viene utilizzata per recuperare informazioni sul file indicato da path. La funzione di callback utilizza due parametri err e stats dove stats è un oggetto che al suo interno ha una serie di informazioni. L'oggetto stats ha inoltre una serie di funzioni che permettono di effettuare delle verifiche sul file stesso: stats.isFile() stats.isDirectory() stats.isBlockDevice() stats.isCharacterDevice() stats.isSymbolicLink() (only valid with fs.lstat()) stats.isFIFO() stats.isSocket() Vediamo ora un esempio per capirne il funzionamento: fs.stat('/tmp/dir', function (err, stats) { if(err) { console.log('error'); }else{ console.log('stats: ' + JSON.stringify(stats)); if(stats.isDirectory()) { console.log("directory"); } } }); I metodi sincroni si riconoscono dal mancato utilizzo della funzione di callback. Vediamo ora alcune delle funzioni sincrone: fs.statSync(path) Questo metodo funziona come fs.stat, ma restituisce l'oggetto stats come risultato della funzione stessa: var stats = fs.statSync('file'); fs.readdirSync(path) 11/15 Dott.Ing.Ivan Ferrazzi Questo metodo funziona come fs.readdir, ma restituisce l'array files come risultato della funzione stessa: var files = fs.readdirSync('dir'); console.log(files.length); Il modulo util Questo modulo contiene una serie di funzioni in grado di ottimizzare il lavoro con le variabili. Il modulo net Questo modulo mette a disposizione uno strumento per la realizzazione di applicativi server-client che si basano sui socket. Il modulo querystring Questo modulo permette di creare una stringa di valori (nome=valore) concatenati dal carattere & da un oggetto e viceversa. La funzione querystring.stringify(obj, [sep], [eq]) permette di creare una stringa da un oggetto mentre la funzione querystring.parse(str, [sep], [eq], [options]) è in grado di fare l'opposto, ossia creare un oggetto da una stringa. Vediamo alcuni semplici esempi: querystring.stringify({ foo: 'bar', baz: ['qux', 'quux'], corge: '' }) restituisce la stringa 'foo=bar&baz=qux&baz=quux&corge=' mentre querystring.stringify({foo: 'bar', baz: 'qux'}, ';', ':') restituisce 'foo:bar;baz:qux' Semplice server http Con il seguente programma vediamo come creare un semplice server http che ad una nostra richiesta risponde con il testo “BUON GIORNO!”. 12/15 Dott.Ing.Ivan Ferrazzi Digitiamo il seguente codice all'interno di un editor di testi e salviamolo con il nome buongiorno.js: var http = require('http'); var server = http.createServer( function (req, res) { res.writeHead(200, {'Content-Type': 'text/html'}); res.write('<html>' + '<head></head>' + '<body>BUON GIORNO!</body>' + '</html>'); res.end(); } ); server.listen(1234, '127.0.0.1'); console.log('server in esecuzione...'); Nella prima riga richiamiamo il modulo http all'interno della variabile oggetto http. Riprendiamo poi l'oggetto per creare il server con createServer che utilizza una funzione callback con i parametri req e res. Nel momento in cui il server risponderà ad una richiesta il sistema richiamerà questa funzione passando la richiesta http come oggetto nella variabile req, mentre l'oggetto res verrà utilizzato per impostare l'eventuale risposta del server. Nel nostro caso utilizziamo quest'ultimo per impostare l'intestazione della risposta con writeHead ed il testo di risposta in chiusura con write. Infine definiamo la porta e l'indirizzo ip sul quale vogliamo attivare il nostro server. Ora facciamo partire il programma con # node buongiorno.js e proviamo ad effettuare una richiesta dal browser con http://localhost:1234 Moduli propri Vediamo ora come poter creare i nostri propri moduli da importare nei nostri codici. Un progetto sviluppato con Node.js utilizza di norma un file di nome index.js all'interno del quale si importano tutti i moduli necessari al buon funzionamento del progetto stesso. Il sistema che utilizza Node.js per riconoscere un file .js come modulo è quello di esportare le funzioni accessibili dall'esterno con la parola exports. Per far diventare modulo il file buongiorno.js creato precedentemente lo modifichiamo come segue: var http = require('http'); function saluto() { 13/15 Dott.Ing.Ivan Ferrazzi } var server = http.createServer( function (req, res) { res.writeHead(200, {'Content-Type': 'text/html'}); res.write('<html>' + '<head></head>' + '<body>BUON GIORNO!</body>' + '</html>'); res.end(); } ); server.listen(1234, '127.0.0.1'); console.log('server in esecuzione...'); exports.saluto = saluto; All'interno del file index.js importiamo il modulo appena creato come segue: var buongiorno = require('./buongiorno'); buongiorno.saluto(); URL parsing La cosa più importante all'interno di un webserver è quella di mandare al client contenuti diversi in base a richieste diverse. Vediamo come poter recuperare le informazioni dalla richiesta inviata dal browser. Partiamo dal seguente esempio: var http = require('http'); var server = http.createServer( function (req, res) { console.log(req.url); res.writeHead(200, {'Content-Type': 'text/html'}); res.write('<html>' + '<head></head>' + '<body>BUON GIORNO!</body>' + '</html>'); res.end(); } ); server.listen(1234, '127.0.0.1'); console.log('server in esecuzione...'); La variabile url dell'oggetto req all'interno della funzione di callback restituisce il percorso alla risorsa richiesta. L'indirizzo url http://localhost:1234 genera il valore url /, mentre la richiesta http://localhost:1234/chisiamo.html genera il valore url /chisiamo.html. Ecco che possiamo utilizzare questa informazione per mandare al browser la pagina richiesta. var http = require('http'); function getHomePage() { 14/15 Dott.Ing.Ivan Ferrazzi } var html = '<html>' + '<head></head>' + '<body>HOMEPAGE</body>' + '</html>'; return html; function getChiSiamo() { var html = '<html>' + '<head></head>' + '<body>CHI SIAMO</body>' + '</html>'; return html; } var server = http.createServer( function (req, res) { console.log(req.url); res.writeHead(200, {'Content-Type': 'text/html'}); var html = ''; if(req.url == '/chisiamo.html') { html = getChiSiamo(); }else{ html = getHomePage(); } res.write(html); res.end(); } ); server.listen(1234, '127.0.0.1'); console.log('server in esecuzione...'); Moduli JSCommon con NPM NPM, oltre ad essere una repository delle librerie scritte per Node.js, è un comando per scaricare, ricercare ed aggiornare i vari software utilizzabili. NPM può essere semplicemente installato con curl come segue # curl http://npmjs.org/install.sh | sh mentre per installare i vari pacchetti si usa # npm install {pacchetto} L'elenco dei moduli disponibili per Node.js si possono trovare all'indirizzo https://npmjs.org/ L'importazione del modulo all'interno del codice si ottiene con la parola require come segue: var modulo = require('{nome_modulo}'); 15/15