Routing
Routing si riferisce a come gli endpoint di un’applicazione (URI) rispondono alle richieste del client. Per un’introduzione al routing, vedere Instradamento di base.
Definisci il routing usando metodi dell’oggetto app Express che corrispondono ai metodi HTTP;
per esempio, app. et() per gestire le richieste GET e app.post per gestire le richieste POST. For a full list,
see app.METHOD. You can also use app.all() to handle all HTTP methods and app.use() to
specify middleware as the callback function (See Using middleware for details).
In altre parole, l’applicazione “ascolta” per le richieste che corrispondono ai percorsi e ai metodi specificati, e quando rileva una corrispondenza, chiama la funzione di callback specificata. In altre parole, l’applicazione “ascolta” per le richieste che corrispondono ai percorsi e ai metodi specificati, e quando rileva una corrispondenza, chiama la funzione di callback specificata.
Infatti, i metodi di routing possono avere più di una funzione di callback come argomenti.
Con funzioni di callback multiple, è importante fornire next come argomento alla funzione di callback e poi chiamare next() all’interno del corpo della funzione per consegnare il controllo
al prossimo callback.
Il seguente codice è un esempio di un percorso molto basilare.
const express = require('express');const app = express();
// respond with "hello world" when a GET request is made to the homepageapp.get('/', (req, res) => { res.send('hello world');});import express from 'express';
const app = express();
// respond with "hello world" when a GET request is made to the homepageapp.get('/', (req, res) => { res.send('hello world');});import express, { type Express, type Request, type Response } from 'express';
const app: Express = express();
// respond with "hello world" when a GET request is made to the homepageapp.get('/', (req: Request, res: Response) => { res.send('hello world');});Metodi percorso
Un metodo di percorso è derivato da uno dei metodi HTTP ed è collegato ad un’istanza della classe express.
Il seguente codice è un esempio di percorsi definiti per il GET e i metodi POST nella root dell’app.
// GET method routeapp.get('/', (req, res) => { res.send('GET request to the homepage');});
// POST method routeapp.post('/', (req, res) => { res.send('POST request to the homepage');});import { type Request, type Response } from 'express';
// GET method routeapp.get('/', (req: Request, res: Response) => { res.send('GET request to the homepage');});
// POST method routeapp.post('/', (req: Request, res: Response) => { res.send('POST request to the homepage');});Express supporta metodi che corrispondono a tutti i metodi di richiesta HTTP: get, post, e così via.
For a full list, see app.METHOD.
C’è un metodo di routing speciale, app.all(), utilizzato per caricare le funzioni middleware in un percorso per tutti i metodi di richiesta HTTP. For example, the following handler is executed for requests to the route "/secret" whether using GET, QUERY, POST, PUT, DELETE, or any other HTTP request method supported in the http module.
app.all('/secret', (req, res, next) => { console.log('Accessing the secret section ...'); next(); // pass control to the next handler});import { type Request, type Response, type NextFunction } from 'express';
app.all('/secret', (req: Request, res: Response, next: NextFunction) => { console.log('Accessing the secret section ...'); next(); // pass control to the next handler});Percorsi di rotta
Percorsi di percorso, in combinazione con un metodo di richiesta, definire gli endpoint in cui le richieste possono essere fatte. I percorsi del percorso possono essere stringhe o espressioni regolari. They can also capture values from the URL, as described in Route parameters below.
Note
Express utilizza path-to-regexp v8 per abbinare i percorsi del percorso; vedere la documentazione path-to-regexp per tutte le possibilità di definire i percorsi del percorso. Express Playground Router è uno strumento utile per testare le rotte Express di base, anche se non supporta la corrispondenza dei modelli.
Tracciati stringhe
I percorsi stringhe corrispondono esattamente alle richieste. Il punto (.) e il trattino (-) sono interpretati letteralmente.
Warning
app.get('/', (req, res) => { res.send('root');});
app.get('/about', (req, res) => { res.send('about');});
app.get('/random.text', (req, res) => { res.send('random.text');});import { type Request, type Response } from 'express';
app.get('/', (req: Request, res: Response) => { res.send('root');});
app.get('/about', (req: Request, res: Response) => { res.send('about');});
app.get('/random.text', (req: Request, res: Response) => { res.send('random.text');});Caution
The characters ?, +, *, [], (), and ! are reserved and cannot be used as literal characters in route paths, and braces are reserved for optional segments. Usa \ per sfuggire se necessario.
Espressioni regolari
È inoltre possibile utilizzare espressioni regolari come percorsi di percorso. Questo è utile quando hai bisogno di una logica di corrispondenza più complessa.
// Matches any path containing "a"app.get(/a/, (req, res) => { res.send('/a/');});
// Matches paths ending with "fly" (butterfly, dragonfly, etc.)app.get(/.*fly$/, (req, res) => { res.send('/.*fly$/');});import { type Request, type Response } from 'express';
// Matches any path containing "a"app.get(/a/, (req: Request, res: Response) => { res.send('/a/');});
// Matches paths ending with "fly" (butterfly, dragonfly, etc.)app.get(/.*fly$/, (req: Request, res: Response) => { res.send('/.*fly$/');});Parametri percorso
I parametri del percorso sono denominati segmenti di URL che vengono utilizzati per catturare i valori specificati nella loro posizione nell’URL. I valori catturati sono popolati nell’oggetto req.params, con il nome del parametro route specificato nel percorso come loro rispettive chiavi. They come in three forms: named parameters (:name), wildcards (*name), and optional segments, which wrap either of them in braces.
Named parameters
Named parameters capture a single path segment at their position in the URL, or part of one when combined with literal characters, as shown further below.
Route path: /users/:userId/books/:bookIdRequest URL: http://localhost:3000/users/34/books/8989req.params: { "userId": "34", "bookId": "8989" }Per definire i percorsi con i parametri del percorso, è sufficiente specificare i parametri del percorso nel percorso come mostrato di seguito.
app.get('/users/:userId/books/:bookId', (req, res) => { res.send(req.params);});In TypeScript, @types/express infers the parameters from the route path, so in the handler above
req.params.userId and req.params.bookId are already typed as string with no extra annotation.
Reading a name that is not in the route (such as req.params.other) is a type error. You only need
to annotate the parameters when the handler is defined separately from the route, because the type
checker can no longer see the path. In that case, pass them as the first type argument of Request:
import { type Request, type Response } from 'express';
const sendParams = (req: Request<{ userId: string; bookId: string }>, res: Response) => { res.send(req.params);};
app.get('/users/:userId/books/:bookId', sendParams);Caution
The name of route parameters must be a valid JavaScript identifier. Other names can be used by quoting them, for example :"user-name".
Poiché il trattino (-) e il punto (.) sono interpretati letteralmente, possono essere utilizzati insieme ai parametri del percorso per scopi utili.
Route path: /flights/:from-:toRequest URL: http://localhost:3000/flights/LAX-SFOreq.params: { "from": "LAX", "to": "SFO" }Route path: /plantae/:genus.:speciesRequest URL: http://localhost:3000/plantae/Prunus.persicareq.params: { "genus": "Prunus", "species": "persica" }Caution
Regexp characters are not supported inside string paths, so a parameter cannot be restricted with a suffix such as :userId(\d+). Use an array of paths or a full regular expression instead.
Per maggiori informazioni consultare il percorso percorso corrispondente alla sintassi.
Wildcards
I caratteri jolly corrispondono a qualsiasi percorso dopo un prefisso. Like other route parameters they must have a name, but they are captured as an array of path segments instead of a string.
app.get('/files/*filepath', (req, res) => { // GET /files/images/logo.png console.dir(req.params.filepath); // => [ 'images', 'logo.png' ] res.send(`File: ${req.params.filepath.join('/')}`);});import { type Request, type Response } from 'express';
app.get('/files/*filepath', (req: Request<{ filepath: string[] }>, res: Response) => { // GET /files/images/logo.png console.dir(req.params.filepath); // => [ 'images', 'logo.png' ] res.send(`File: ${req.params.filepath.join('/')}`);});Per abbinare anche il percorso di root, avvolgere il wildcard in graffe:
// Matches / , /foo , /foo/bar , etc.app.get('/{*splat}', (req, res) => { // GET / => req.params = {}, splat is omitted // GET /foo/bar => req.params.splat = [ 'foo', 'bar' ] res.send('ok');});import { type Request, type Response } from 'express';
// Matches / , /foo , /foo/bar , etc.app.get('/{*splat}', (req: Request, res: Response) => { // GET / => req.params = {}, splat is omitted // GET /foo/bar => req.params.splat = [ 'foo', 'bar' ] res.send('ok');});Segmenti facoltativi
Usa le parentesi graffe per definire segmenti opzionali in un percorso percorso. Quando il segmento non è presente, il parametro viene omesso da req.params.
app.get('/:file{.:ext}', (req, res) => { // GET /image.png => req.params = { file: 'image', ext: 'png' } // GET /image => req.params = { file: 'image' } res.send('ok');});import { type Request, type Response } from 'express';
app.get('/:file{.:ext}', (req: Request, res: Response) => { // GET /image.png => req.params = { file: 'image', ext: 'png' } // GET /image => req.params = { file: 'image' } res.send('ok');});The braces can also wrap a whole parameter to make it optional. Note that everything inside the braces is optional, so the position of the slash matters:
app.get('/user/{:id}', (req, res) => { // GET /user/42 => req.params = { id: '42' } // GET /user/ => req.params = {} // GET /user => 404, only the parameter is optional res.send('ok');});
app.get('/order{/:id}', (req, res) => { // GET /order/42 => req.params = { id: '42' } // GET /order => req.params = {}, the whole segment is optional res.send('ok');});import { type Request, type Response } from 'express';
app.get('/user/{:id}', (req: Request, res: Response) => { // GET /user/42 => req.params = { id: '42' } // GET /user/ => req.params = {} // GET /user => 404, only the parameter is optional res.send('ok');});
app.get('/order{/:id}', (req: Request, res: Response) => { // GET /order/42 => req.params = { id: '42' } // GET /order => req.params = {}, the whole segment is optional res.send('ok');});Non confondere la posizione della barra nel percorso della rotta con l’impostazione strict routing, che riguarda l’URL della richiesta: controlla se un URL che termina con una barra non richiesta dal percorso della rotta corrisponde comunque. Ad esempio, una richiesta a /order/ corrisponde per impostazione predefinita alla rotta /order{/:id}, ma restituisce un errore 404 quando strict routing è abilitato; la barra finale di /user/ non è interessata perché la rotta /user/{:id} la richiede. Tutte le richieste commentate negli esempi precedenti si comportano allo stesso modo indipendentemente da questa impostazione.
Gestori del percorso
È possibile fornire più funzioni di callback che si comportano come middleware per gestire una richiesta. L’unica eccezione è che questi callback potrebbero invocare next('route') per bypassare i rimanenti callback del percorso. È possibile utilizzare questo meccanismo per imporre condizioni preliminari su un percorso, poi passare il controllo ai percorsi successivi se non c’è motivo di procedere con il percorso corrente.
app.get('/user/:id', (req, res, next) => { if (req.params.id === '0') { return next('route'); } res.send(`User ${req.params.id}`);});
app.get('/user/:id', (req, res) => { res.send('Special handler for user ID 0');});import { type Request, type Response, type NextFunction } from 'express';
app.get('/user/:id', (req: Request, res: Response, next: NextFunction) => { if (req.params.id === '0') { return next('route'); } res.send(`User ${req.params.id}`);});
app.get('/user/:id', (req: Request, res: Response) => { res.send('Special handler for user ID 0');});In questo esempio:
GET /user/5→ gestito dal primo percorso → invia “User 5”GET /user/0→ prima rotta chiamanext('route'), saltando al prossimo percorso corrispondente/user/:id
I gestori del percorso possono essere nella forma di una funzione, una serie di funzioni, o combinazioni di entrambi, come mostrato negli esempi seguenti.
Una singola funzione di callback può gestire un percorso. Per esempio:
app.get('/example/a', (req, res) => { res.send('Hello from A!');});import { type Request, type Response } from 'express';
app.get('/example/a', (req: Request, res: Response) => { res.send('Hello from A!');});Più di una funzione di callback può gestire un percorso (assicurati di specificare l’oggetto next). Per esempio:
app.get( '/example/b', (req, res, next) => { console.log('the response will be sent by the next function ...'); next(); }, (req, res) => { res.send('Hello from B!'); });import { type Request, type Response, type NextFunction } from 'express';
app.get( '/example/b', (req: Request, res: Response, next: NextFunction) => { console.log('the response will be sent by the next function ...'); next(); }, (req: Request, res: Response) => { res.send('Hello from B!'); });Un array di funzioni di callback può gestire un percorso. Per esempio:
const cb0 = function (req, res, next) { console.log('CB0'); next();};
const cb1 = function (req, res, next) { console.log('CB1'); next();};
const cb2 = function (req, res) { res.send('Hello from C!');};
app.get('/example/c', [cb0, cb1, cb2]);import { type Request, type Response, type NextFunction } from 'express';
const cb0 = function (req: Request, res: Response, next: NextFunction) { console.log('CB0'); next();};
const cb1 = function (req: Request, res: Response, next: NextFunction) { console.log('CB1'); next();};
const cb2 = function (req: Request, res: Response) { res.send('Hello from C!');};
app.get('/example/c', [cb0, cb1, cb2]);Una combinazione di funzioni indipendenti e matrici di funzioni può gestire un percorso. Per esempio:
const cb0 = function (req, res, next) { console.log('CB0'); next();};
const cb1 = function (req, res, next) { console.log('CB1'); next();};
app.get( '/example/d', [cb0, cb1], (req, res, next) => { console.log('the response will be sent by the next function ...'); next(); }, (req, res) => { res.send('Hello from D!'); });import { type Request, type Response, type NextFunction } from 'express';
const cb0 = function (req: Request, res: Response, next: NextFunction) { console.log('CB0'); next();};
const cb1 = function (req: Request, res: Response, next: NextFunction) { console.log('CB1'); next();};
app.get( '/example/d', [cb0, cb1], (req: Request, res: Response, next: NextFunction) => { console.log('the response will be sent by the next function ...'); next(); }, (req: Request, res: Response) => { res.send('Hello from D!'); });Metodi di risposta
The methods on the response object (res) in the following table can send a response to the client, and terminate the request-response cycle. Se nessuno di questi metodi è chiamato da un gestore del percorso, la richiesta del cliente sarà sospesa.
| Metodo | Descrizione |
|---|---|
| res.download() | Avverte un file da scaricare. |
| res.end() | Termina il processo di risposta. |
| res.json() | Invia una risposta JSON. |
| res.jsonp() | Invia una risposta JSON con il supporto JSONP. |
| res.redirect() | Reindirizza una richiesta. |
| res.render() | Render un modello di visualizzazione. |
| res.send() | Invia una risposta di vari tipi. |
| res.sendFile() | Invia un file come un flusso di otte. |
| res.sendStatus() | Imposta il codice di stato della risposta e invia la sua rappresentazione della stringa come corpo della risposta. |
app.route()
È possibile creare i gestori di rotte per un percorso utilizzando app.route().
Because the path is specified in a single location, this helps to create modular routes and reduces redundancy and typos. For more information about routes, see the Router() documentation.
Ecco un esempio di router incatenati che sono definiti utilizzando app.route().
app .route('/book') .get((req, res) => { res.send('Get a random book'); }) .post((req, res) => { res.send('Add a book'); }) .put((req, res) => { res.send('Update the book'); });import { type Request, type Response } from 'express';
app .route('/book') .get((req: Request, res: Response) => { res.send('Get a random book'); }) .post((req: Request, res: Response) => { res.send('Add a book'); }) .put((req: Request, res: Response) => { res.send('Update the book'); });express.Router
Usa la classe express.Router per creare i gestori modulari e montabili. Un’istanza Router è un sistema di routing e middleware completo; per questo motivo è spesso chiamata “mini-app”.
L’esempio seguente crea un router come modulo, carica una funzione middleware in esso, definisce alcuni percorsi e monta il modulo del router su un percorso nell’app principale.
Crea un file router chiamato birds.js nella directory delle app, con il seguente contenuto:
const express = require('express');const router = express.Router();
// middleware that is specific to this routerconst timeLog = (req, res, next) => { console.log('Time: ', Date.now()); next();};router.use(timeLog);
// define the home page routerouter.get('/', (req, res) => { res.send('Birds home page');});// define the about routerouter.get('/about', (req, res) => { res.send('About birds');});
module.exports = router;import express from 'express';
const router = express.Router();
// middleware that is specific to this routerconst timeLog = (req, res, next) => { console.log('Time: ', Date.now()); next();};router.use(timeLog);
// define the home page routerouter.get('/', (req, res) => { res.send('Birds home page');});// define the about routerouter.get('/about', (req, res) => { res.send('About birds');});
export default router;import express, { type Request, type Response, type NextFunction } from 'express';
const router = express.Router();
// middleware that is specific to this routerconst timeLog = (req: Request, res: Response, next: NextFunction) => { console.log('Time: ', Date.now()); next();};router.use(timeLog);
// define the home page routerouter.get('/', (req: Request, res: Response) => { res.send('Birds home page');});// define the about routerouter.get('/about', (req: Request, res: Response) => { res.send('About birds');});
export default router;Quindi, caricare il modulo router nell’app:
const birds = require('./birds');
// ...
app.use('/birds', birds);import birds from './birds';
// ...
app.use('/birds', birds);L’app sarà ora in grado di gestire le richieste di /birds e /birds/about, oltre a chiamare la funzione middleware timeLog che è specifica per il percorso.
Ma se il percorso principale /birds ha parametri di percorso, non sarà accessibile per impostazione predefinita dai sotto-percorsi. To make it accessible, you will need to pass the mergeParams option to the Router constructor.
const router = express.Router({ mergeParams: true });