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).
These routing methods specify a callback function (sometimes called a “handler function”) that Express automatically runs when the application receives a request matching the specified route (endpoint) and HTTP method. 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.
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');});Wildcards
I caratteri jolly corrispondono a qualsiasi percorso dopo un prefisso. Devono avere un nome, proprio come i parametri del percorso, e sono catturati come array di segmenti di percorso.
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 = [] // 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 = [] // 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');});I caratteri ?, +, *, [], e () sono riservati e non possono essere usati come caratteri letterali nei percorsi del percorso. 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.
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);Il nome dei parametri del percorso deve essere composto da “caratteri di parola” ([A-Za-z0-9_]).
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" }I caratteri Regexp non sono supportati nei percorsi del percorso. Usa invece un array di tracciati o espressioni regolari. Per maggiori informazioni consultare il percorso percorso corrispondente alla sintassi.
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
I metodi sull’oggetto di risposta (res) nella tabella seguente possono inviare una risposta al client e terminare il ciclo di richiesta-risposta. 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().
Poiché il percorso è specificato in una singola posizione, è utile creare percorsi modulari, così come ridurre la ridondanza e pneumatici. Per ulteriori informazioni sulle rotte, si veda: 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 reference.
const router = express.Router({ mergeParams: true });