Node.js
App Web con Express
Ricerca…
introduzione
Express è un framework di applicazioni web Node.js minimale e flessibile, che fornisce un robusto set di funzionalità per la creazione di applicazioni Web.
Il sito web ufficiale di Express è expressjs.com . La fonte può essere trovata su GitHub .
Sintassi
- app.get (percorso [, middleware], callback [, callback ...])
- app.put (percorso [, middleware], callback [, callback ...])
- app.post (percorso [, middleware], callback [, callback ...])
- app ['delete'] (percorso [, middleware], callback [, callback ...])
- app.use (percorso [, middleware], callback [, callback ...])
- app.use (callback)
Parametri
Parametro | Dettagli |
---|---|
path | Specifica la parte del percorso o l'URL che verrà gestito dal callback specificato. |
middleware | Una o più funzioni che verranno chiamate prima della richiamata. Essenzialmente un concatenamento di più funzioni di callback . Utile per una gestione più specifica, ad esempio l'autorizzazione o la gestione degli errori. |
callback | Una funzione che verrà utilizzata per gestire le richieste nel path specificato. Sarà chiamato come callback(request, response, next) , dove request , response e next sono descritti di seguito. |
request richiamata | Un oggetto che incapsula i dettagli sulla richiesta HTTP che il callback è stato chiamato a gestire. |
response | Un oggetto che viene utilizzato per specificare in che modo il server deve rispondere alla richiesta. |
next | Un callback che passa il controllo sulla prossima route corrispondente. Accetta un oggetto errore opzionale. |
Iniziare
Dovrai prima creare una directory, accedervi nella tua shell e installare Express usando npm eseguendo npm install express --save
Crea un file e app.js
e aggiungi il codice seguente che crea un nuovo server Express e aggiunge un endpoint ( /ping
) con il metodo app.get
:
const express = require('express');
const app = express();
app.get('/ping', (request, response) => {
response.send('pong');
});
app.listen(8080, 'localhost');
Per eseguire il tuo script usa il seguente comando nella tua shell:
> node app.js
La tua applicazione accetterà le connessioni sulla porta localhost 8080. Se l'argomento nome host per app.listen
viene omesso, il server accetterà le connessioni sull'indirizzo IP della macchina e su localhost. Se il valore della porta è 0, il sistema operativo assegnerà una porta disponibile.
Una volta che lo script è in esecuzione, puoi testarlo in una shell per confermare che ottieni la risposta prevista, "pong", dal server:
> curl http://localhost:8080/ping
pong
È anche possibile aprire un browser Web, accedere all'URL http: // localhost: 8080 / ping per visualizzare l'output
Routing di base
Per prima cosa crea un'app express:
const express = require('express');
const app = express();
Quindi puoi definire percorsi come questo:
app.get('/someUri', function (req, res, next) {})
Questa struttura funziona per tutti i metodi HTTP e prevede un percorso come primo argomento e un gestore per quel percorso, che riceve gli oggetti richiesta e risposta. Quindi, per i metodi HTTP di base, questi sono i percorsi
// GET www.domain.com/myPath
app.get('/myPath', function (req, res, next) {})
// POST www.domain.com/myPath
app.post('/myPath', function (req, res, next) {})
// PUT www.domain.com/myPath
app.put('/myPath', function (req, res, next) {})
// DELETE www.domain.com/myPath
app.delete('/myPath', function (req, res, next) {})
Puoi controllare l'elenco completo dei verbi supportati qui . Se si desidera definire lo stesso comportamento per una route e tutti i metodi HTTP, è possibile utilizzare:
app.all('/myPath', function (req, res, next) {})
o
app.use('/myPath', function (req, res, next) {})
o
app.use('*', function (req, res, next) {})
// * wildcard will route for all paths
È possibile concatenare le definizioni del percorso per un singolo percorso
app.route('/myPath')
.get(function (req, res, next) {})
.post(function (req, res, next) {})
.put(function (req, res, next) {})
È inoltre possibile aggiungere funzioni a qualsiasi metodo HTTP. Eseguiranno prima del callback finale e prenderanno come parametri i parametri (req, res, next).
// GET www.domain.com/myPath
app.get('/myPath', myFunction, function (req, res, next) {})
Le tue callback finali possono essere archiviate in un file esterno per evitare di inserire troppo codice in un file:
// other.js
exports.doSomething = function(req, res, next) {/* do some stuff */};
E poi nel file contenente i tuoi percorsi:
const other = require('./other.js');
app.get('/someUri', myFunction, other.doSomething);
Questo renderà il tuo codice molto più pulito.
Ottenere informazioni dalla richiesta
Per ottenere informazioni dall'URL richiedente (notare che req
è l'oggetto richiesta nella funzione di gestione dei percorsi). Considera questa definizione di percorso /settings/:user_id
e questo particolare esempio /settings/32135?field=name
// get the full path
req.originalUrl // => /settings/32135?field=name
// get the user_id param
req.params.user_id // => 32135
// get the query value of the field
req.query.field // => 'name'
Puoi anche ottenere intestazioni della richiesta, come questa
req.get('Content-Type')
// "text/plain"
Per semplificare l'acquisizione di altre informazioni puoi usare i middleware. Ad esempio, per ottenere le informazioni sulla body della richiesta, è possibile utilizzare il middleware body-parser , che trasformerà il corpo della richiesta grezza in formato utilizzabile.
var app = require('express')();
var bodyParser = require('body-parser');
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
Supponiamo ora una richiesta come questa
PUT /settings/32135
{
"name": "Peter"
}
Puoi accedere al nome postato come questo
req.body.name
// "Peter"
In modo simile, puoi accedere ai cookie dalla richiesta, hai anche bisogno di un middleware come cookie-parser
req.cookies.name
Applicazione espressa modulare
Per rendere le fabbriche di router di applicazioni modulari per uso express:
Modulo:
// greet.js
const express = require('express');
module.exports = function(options = {}) { // Router factory
const router = express.Router();
router.get('/greet', (req, res, next) => {
res.end(options.greeting);
});
return router;
};
Applicazione:
// app.js
const express = require('express');
const greetMiddleware = require('./greet.js');
express()
.use('/api/v1/', greetMiddleware({ greeting:'Hello world' }))
.listen(8080);
Ciò renderà la tua applicazione modulare, personalizzabile e il tuo codice riutilizzabile.
Quando si accede a http://<hostname>:8080/api/v1/greet
l'output sarà Hello world
Esempio più complicato
Esempio con servizi che mostrano vantaggi di fabbrica del middleware.
Modulo:
// greet.js
const express = require('express');
module.exports = function(options = {}) { // Router factory
const router = express.Router();
// Get controller
const {service} = options;
router.get('/greet', (req, res, next) => {
res.end(
service.createGreeting(req.query.name || 'Stranger')
);
});
return router;
};
Applicazione:
// app.js
const express = require('express');
const greetMiddleware = require('./greet.js');
class GreetingService {
constructor(greeting = 'Hello') {
this.greeting = greeting;
}
createGreeting(name) {
return `${this.greeting}, ${name}!`;
}
}
express()
.use('/api/v1/service1', greetMiddleware({
service: new GreetingService('Hello'),
}))
.use('/api/v1/service2', greetMiddleware({
service: new GreetingService('Hi'),
}))
.listen(8080);
Quando si accede a http://<hostname>:8080/api/v1/service1/greet?name=World
l'output sarà Hello, World
e accederà a http://<hostname>:8080/api/v1/service2/greet?name=World
l'output sarà Hi, World
.
Utilizzo di un motore di modelli
Utilizzo di un motore di modelli
Il codice seguente configurerà Jade come motore di template. (Nota: Jade è stata ribattezzata come pug
a dicembre 2015.)
const express = require('express'); //Imports the express module
const app = express(); //Creates an instance of the express module
const PORT = 3000; //Randomly chosen port
app.set('view engine','jade'); //Sets jade as the View Engine / Template Engine
app.set('views','src/views'); //Sets the directory where all the views (.jade files) are stored.
//Creates a Root Route
app.get('/',function(req, res){
res.render('index'); //renders the index.jade file into html and returns as a response. The render function optionally takes the data to pass to the view.
});
//Starts the Express server with a callback
app.listen(PORT, function(err) {
if (!err) {
console.log('Server is running at port', PORT);
} else {
console.log(JSON.stringify(err));
}
});
Allo stesso modo, potrebbero essere utilizzati anche altri modelli di template come Handlebars
( hbs
) o ejs
. Ricorda di npm install
il motore di template. Per Handlebars utilizziamo il pacchetto hbs
, per Jade abbiamo un pacchetto jade
e per EJS abbiamo un pacchetto ejs
.
Esempio di modello EJS
Con EJS (come altri modelli express), puoi eseguire il codice del server e accedere alle tue variabili del server dal tuo HTML.
In EJS è fatto usando " <%
" come tag di inizio e " %>
" come tag di fine, le variabili passate come parametri di rendering sono accessibili usando <%=var_name%>
Ad esempio, se si dispone di array di forniture nel codice del server
puoi ricollegarlo usando
<h1><%= title %></h1>
<ul>
<% for(var i=0; i<supplies.length; i++) { %>
<li>
<a href='supplies/<%= supplies[i] %>'>
<%= supplies[i] %>
</a>
</li>
<% } %>
Come puoi vedere nell'esempio ogni volta che cambi codice server e HTML devi chiudere il tag EJS corrente e aprirne uno successivo, qui abbiamo voluto creare li
dentro il comando for
quindi abbiamo dovuto chiudere il nostro tag EJS alla fine del for
e crea un nuovo tag solo per le parentesi graffe
un altro esempio
se vogliamo inserire la versione predefinita di input come variabile dal lato server, usiamo <%=
per esempio:
Message:<br>
<input type="text" value="<%= message %>" name="message" required>
Qui la variabile del messaggio passata dal lato server sarà il valore predefinito del tuo input, tieni presente che se non hai passato la variabile del messaggio dal lato server, EJS genererà un'eccezione. Puoi passare i parametri usando res.render('index', {message: message});
(per il file ejs chiamato index.ejs).
Nei tag EJS puoi anche utilizzare if
, while
o qualsiasi altro comando javascript che desideri.
API JSON con ExpressJS
var express = require('express');
var cors = require('cors'); // Use cors module for enable Cross-origin resource sharing
var app = express();
app.use(cors()); // for all routes
var port = process.env.PORT || 8080;
app.get('/', function(req, res) {
var info = {
'string_value': 'StackOverflow',
'number_value': 8476
}
res.json(info);
// or
/* res.send(JSON.stringify({
string_value: 'StackOverflow',
number_value: 8476
})) */
//you can add a status code to the json response
/* res.status(200).json(info) */
})
app.listen(port, function() {
console.log('Node.js listening on port ' + port)
})
Su http://localhost:8080/
oggetto di output
{
string_value: "StackOverflow",
number_value: 8476
}
Servire file statici
Quando si crea un server Web con Express, è spesso richiesto di offrire una combinazione di contenuti dinamici e file statici.
Ad esempio, potresti avere index.html e script.js che sono file statici mantenuti nel file system.
È comune utilizzare la cartella denominata "public" per avere file statici. In questo caso la struttura della cartella potrebbe essere simile a:
project root
├── server.js
├── package.json
└── public
├── index.html
└── script.js
Ecco come configurare Express per servire file statici:
const express = require('express');
const app = express();
app.use(express.static('public'));
Nota: una volta configurata la cartella, index.html, script.js e tutti i file nella cartella "pubblica" saranno disponibili nel percorso principale (non è necessario specificare /public/
nell'URL). Questo perché, express cerca i file relativi alla cartella statica configurata. È possibile specificare il prefisso del percorso virtuale come mostrato di seguito:
app.use('/static', express.static('public'));
renderà le risorse disponibili sotto /static/
prefisso.
Più cartelle
È possibile definire più cartelle contemporaneamente:
app.use(express.static('public'));
app.use(express.static('images'));
app.use(express.static('files'));
Quando serve le risorse Express esaminerà la cartella nell'ordine di definizione. In caso di file con lo stesso nome, verrà pubblicato quello nella prima cartella di corrispondenza.
Percorsi con nomi in stile Django
Un grosso problema è che le rotte con nome prezioso non sono supportate da Express out of the box. La soluzione è installare il pacchetto di terze parti supportato, ad esempio express-reverse :
npm install express-reverse
Collegalo al tuo progetto:
var app = require('express')();
require('express-reverse')(app);
Quindi usarlo come:
app.get('test', '/hello', function(req, res) {
res.end('hello');
});
Lo svantaggio di questo approccio è che non è possibile utilizzare il modulo Express route
come mostrato nell'utilizzo avanzato del router . La soluzione alternativa è passare la tua app
come parametro alla tua fabbrica di router:
require('./middlewares/routing')(app);
E usalo come:
module.exports = (app) => {
app.get('test', '/hello', function(req, res) {
res.end('hello');
});
};
Da ora in poi puoi capire come definire le funzioni per unirle con spazi dei nomi personalizzati specificati e puntare ai controller appropriati.
Gestione degli errori
Gestione degli errori di base
Per impostazione predefinita, Express cercherà una vista "errore" nella directory /views
per il rendering. Basta creare la vista 'errore' e posizionarla nella directory views per gestire gli errori. Gli errori vengono scritti con il messaggio di errore, lo stato e la traccia dello stack, ad esempio:
views / error.pug
html
body
h1= message
h2= error.status
p= error.stack
Gestione avanzata degli errori
Definisci le tue funzioni middleware di gestione degli errori alla fine dello stack di funzioni middleware. Questi hanno quattro argomenti invece di tre (err, req, res, next)
per esempio:
app.js
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
//pass error to the next matching route.
next(err);
});
// handle error, print stacktrace
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
È possibile definire diverse funzioni middleware di gestione degli errori, proprio come si farebbe con le normali funzioni middleware.
Utilizzo del middleware e della prossima richiamata
Express passa una next
richiamata a tutte le funzioni di gestore di route e middleware che possono essere utilizzate per interrompere la logica per rotte singole su più gestori. La chiamata a next()
senza argomenti indica a express di continuare con il prossimo middleware o gestore di route corrispondente. Se si chiama next(err)
con un errore, verrà attivato qualsiasi middleware del gestore degli errori. La chiamata next('route')
ignorerà qualsiasi middleware successivo sulla rotta corrente e passerà alla successiva route corrispondente. Ciò consente di disaccoppiare la logica del dominio in componenti riutilizzabili che sono autonomi, più semplici da testare e più facili da mantenere e modificare.
Più percorsi di corrispondenza
Le richieste a /api/foo
o a /api/bar
eseguiranno il gestore iniziale per cercare il membro e quindi passare il controllo al gestore effettivo per ogni percorso.
app.get('/api', function(req, res, next) {
// Both /api/foo and /api/bar will run this
lookupMember(function(err, member) {
if (err) return next(err);
req.member = member;
next();
});
});
app.get('/api/foo', function(req, res, next) {
// Only /api/foo will run this
doSomethingWithMember(req.member);
});
app.get('/api/bar', function(req, res, next) {
// Only /api/bar will run this
doSomethingDifferentWithMember(req.member);
});
Gestore degli errori
I gestori degli errori sono middleware con la function(err, req, res, next)
firma function(err, req, res, next)
. Possono essere impostati per percorso (ad esempio app.get('/foo', function(err, req, res, next)
) ma in genere, un singolo gestore di errori che esegue il rendering di una pagina di errore è sufficiente.
app.get('/foo', function(req, res, next) {
doSomethingAsync(function(err, data) {
if (err) return next(err);
renderPage(data);
});
});
// In the case that doSomethingAsync return an error, this special
// error handler middleware will be called with the error as the
// first parameter.
app.use(function(err, req, res, next) {
renderErrorPage(err);
});
middleware
Ciascuna delle funzioni di cui sopra è in realtà una funzione middleware che viene eseguita ogni volta che una richiesta corrisponde alla rotta definita, ma qualsiasi numero di funzioni middleware può essere definito su una singola rotta. Ciò consente di definire il middleware in file separati e la logica comune da riutilizzare su più percorsi.
app.get('/bananas', function(req, res, next) {
getMember(function(err, member) {
if (err) return next(err);
// If there's no member, don't try to look
// up data. Just go render the page now.
if (!member) return next('route');
// Otherwise, call the next middleware and fetch
// the member's data.
req.member = member;
next();
});
}, function(req, res, next) {
getMemberData(req.member, function(err, data) {
if (err) return next(err);
// If this member has no data, don't bother
// parsing it. Just go render the page now.
if (!data) return next('route');
// Otherwise, call the next middleware and parse
// the member's data. THEN render the page.
req.member.data = data;
next();
});
}, function(req, res, next) {
req.member.parsedData = parseMemberData(req.member.data);
next();
});
app.get('/bananas', function(req, res, next) {
renderBananas(req.member);
});
In questo esempio, ciascuna funzione middleware potrebbe trovarsi nel proprio file o in una variabile altrove nel file in modo che possa essere riutilizzata in altre route.
Gestione degli errori
I documenti di base possono essere trovati qui
app.get('/path/:id(\\d+)', function (req, res, next) { // please note: "next" is passed
if (req.params.id == 0) // validate param
return next(new Error('Id is 0')); // go to first Error handler, see below
// Catch error on sync operation
var data;
try {
data = JSON.parse('/file.json');
} catch (err) {
return next(err);
}
// If some critical error then stop application
if (!data)
throw new Error('Smth wrong');
// If you need send extra info to Error handler
// then send custom error (see Appendix B)
if (smth)
next(new MyError('smth wrong', arg1, arg2))
// Finish request by res.render or res.end
res.status(200).end('OK');
});
// Be sure: order of app.use have matter
// Error handler
app.use(function(err, req, res, next)) {
if (smth-check, e.g. req.url != 'POST')
return next(err); // go-to Error handler 2.
console.log(req.url, err.message);
if (req.xhr) // if req via ajax then send json else render error-page
res.json(err);
else
res.render('error.html', {error: err.message});
});
// Error handler 2
app.use(function(err, req, res, next)) {
// do smth here e.g. check that error is MyError
if (err instanceof MyError) {
console.log(err.message, err.arg1, err.arg2);
}
...
res.end();
});
Appendice A
// "In Express, 404 responses are not the result of an error,
// so the error-handler middleware will not capture them."
// You can change it.
app.use(function(req, res, next) {
next(new Error(404));
});
Appendice B
// How to define custom error
var util = require('util');
...
function MyError(message, arg1, arg2) {
this.message = message;
this.arg1 = arg1;
this.arg2 = arg2;
Error.captureStackTrace(this, MyError);
}
util.inherits(MyError, Error);
MyError.prototype.name = 'MyError';
Hook: come eseguire il codice prima di qualsiasi req e dopo qualsiasi res
app.use()
e middleware possono essere utilizzati per "before" e una combinazione di eventi close e finish può essere utilizzata per "after".
app.use(function (req, res, next) {
function afterResponse() {
res.removeListener('finish', afterResponse);
res.removeListener('close', afterResponse);
// actions after response
}
res.on('finish', afterResponse);
res.on('close', afterResponse);
// action before request
// eventually calling `next()`
next();
});
...
app.use(app.router);
Un esempio di questo è il middleware del logger , che verrà aggiunto al log dopo la risposta per impostazione predefinita.
Assicurati che questo "middleware" sia utilizzato prima di app.router
quanto l'ordine è importante.
Il post originale è qui
Gestire richieste POST
Proprio come gestisci le richieste get in Express con il metodo app.get, puoi utilizzare il metodo app.post per gestire le richieste post.
Ma prima di poter gestire le richieste POST, sarà necessario utilizzare il middleware body-parser
. Semplicemente analizza il corpo di POST
, PUT
, DELETE
e altre richieste.
Body-Parser
middleware Body-Parser
analizza il corpo della richiesta e lo trasforma in un oggetto disponibile in req.body
var bodyParser = require('body-parser');
const express = require('express');
const app = express();
// Parses the body for POST, PUT, DELETE, etc.
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/post-data-here', function(req, res, next){
console.log(req.body); // req.body contains the parsed body of the request.
});
app.listen(8080, 'localhost');
Impostazione dei cookie con cookie-parser
Di seguito è riportato un esempio per l'impostazione e la lettura dei cookie utilizzando il modulo cookie-parser :
var express = require('express');
var cookieParser = require('cookie-parser'); // module for parsing cookies
var app = express();
app.use(cookieParser());
app.get('/setcookie', function(req, res){
// setting cookies
res.cookie('username', 'john doe', { maxAge: 900000, httpOnly: true });
return res.send('Cookie has been set');
});
app.get('/getcookie', function(req, res) {
var username = req.cookies['username'];
if (username) {
return res.send(username);
}
return res.send('No cookie found');
});
app.listen(3000);
Middleware personalizzato in Express
In Express, è possibile definire i middleware che possono essere utilizzati per controllare le richieste o impostare alcune intestazioni in risposta.
app.use(function(req, res, next){ }); // signature
Esempio
Il codice seguente aggiunge l' user
all'oggetto richiesta e passa il controllo alla successiva route corrispondente.
var express = require('express');
var app = express();
//each request will pass through it
app.use(function(req, res, next){
req.user = 'testuser';
next(); // it will pass the control to next matching route
});
app.get('/', function(req, res){
var user = req.user;
console.log(user); // testuser
return res.send(user);
});
app.listen(3000);
Gestione degli errori in Express
In Express, è possibile definire un gestore di errori unificato per la gestione degli errori verificatisi nell'applicazione. Definire quindi il gestore alla fine di tutti i percorsi e il codice logico.
Esempio
var express = require('express');
var app = express();
//GET /names/john
app.get('/names/:name', function(req, res, next){
if (req.params.name == 'john'){
return res.send('Valid Name');
} else{
next(new Error('Not valid name')); //pass to error handler
}
});
//error handler
app.use(function(err, req, res, next){
console.log(err.stack); // e.g., Not valid name
return res.status(500).send('Internal Server Occured');
});
app.listen(3000);
Aggiunta di middleware
Le funzioni middleware sono funzioni che hanno accesso all'oggetto richiesta (req), all'oggetto risposta (res) e alla funzione middleware successiva nel ciclo richiesta-risposta dell'applicazione.
Le funzioni middleware possono eseguire qualsiasi codice, apportare modifiche agli oggetti res
e req
, al ciclo di risposta finale e chiamare il prossimo middleware.
Esempio molto comune di middleware è il modulo cors
. Per aggiungere il supporto CORS, è sufficiente installarlo, richiederlo e inserire questa riga:
app.use(cors());
prima di qualsiasi router o funzione di routing.
Ciao mondo
Qui creiamo un semplice server mondiale Hello usando Express. Itinerari:
- '/'
- '/ Wiki'
E per il riposo darà "404", cioè la pagina non trovata.
'use strict';
const port = process.env.PORT || 3000;
var app = require('express')();
app.listen(port);
app.get('/',(req,res)=>res.send('HelloWorld!'));
app.get('/wiki',(req,res)=>res.send('This is wiki page.'));
app.use((req,res)=>res.send('404-PageNotFound'));
Nota: abbiamo inserito la rotta 404 come ultima rotta mentre Express impila i percorsi in ordine e li elabora in sequenza per ogni richiesta.