Node.js / Express.js - Come funziona app.router?


298

Prima di chiedere, app.routerpenso che dovrei spiegare almeno cosa penso che accada quando si lavora con il middleware. Per utilizzare il middleware, la funzione da utilizzare è app.use(). Quando il middleware viene eseguito, chiamerà il middleware successivo usando next()o lo farà in modo che non venga più chiamato middleware. Ciò significa che l'ordine in cui inserisco le chiamate del mio middleware è importante, poiché alcuni middleware dipendono da altri middleware e alcuni middleware vicino alla fine potrebbero non essere nemmeno chiamati.

Oggi stavo lavorando sulla mia applicazione e il mio server era in esecuzione in background. Volevo apportare alcune modifiche e aggiornare la mia pagina e vedere immediatamente le modifiche. In particolare, stavo apportando modifiche al mio layout. Non sono riuscito a farlo funzionare, quindi ho cercato Stack Overflow per la risposta e ho trovato questa domanda . Dice per assicurarsi che express.static()sia sotto require('stylus'). Ma quando stavo guardando il codice di quell'OP, ho visto che aveva la sua app.routerchiamata proprio alla fine delle sue chiamate sul middleware, e ho cercato di capire perché fosse così.

Quando ho fatto la mia domanda Express.js (versione 3.0.0rc4), ho usato il comando express app --sessions --css styluse il mio file app.js il codice venuto messa a punto con il mio app.routeral di sopra sia del express.static()e require('stylus')chiamate. Quindi sembra che, se arriva già impostato in quel modo, allora dovrebbe rimanere tale.

Dopo aver riorganizzato il mio codice in modo da poter vedere le modifiche dello stilo, è simile al seguente:

app.configure(function(){
  //app.set() calls
  //app.use() calls
  //...
  app.use(app.router);
  app.use(require('stylus').middleware(__dirname + '/public'));
  app.use(express.static(__dirname + '/public', {maxAge: 31557600000}));
});

app.get('/', routes.index);

app.get('/test', function(req, res){
  res.send('Test');
});

Quindi ho deciso che il primo passo sarebbe stato scoprire perché è importante avere anche app.routernel mio codice. Quindi l'ho commentato, ho avviato la mia app e sono passato a /. Ha mostrato la mia pagina indice proprio bene. Hmm, forse ha funzionato perché stavo esportando il routing dal mio file di route (route.index). Quindi ho navigato /teste ho visualizzato Test sullo schermo. Haha, OK, non ho idea di cosa app.routerfaccia. Che sia incluso nel mio codice o meno, il mio routing va bene. Quindi mi manca decisamente qualcosa.

Quindi questa è la mia domanda:

Qualcuno potrebbe spiegare cosa app.routerfa, l'importanza di esso e dove dovrei inserirlo nelle mie chiamate di middleware? Sarebbe anche bello se avessi una breve spiegazione in merito express.static(). Per quanto posso dire, express.static()è una cache delle mie informazioni e se l'applicazione non riesce a trovare la pagina richiesta, controllerà la cache per vedere se esiste.


18
Grazie per aver posto questa domanda. Ho cercato su Google per trovare questa risposta (e la domanda per chiederla).
Hari Seldon,

8
Era una domanda davvero ben scritta, stavo cercando su Google la stessa cosa.
Kirn

Risposte:


329

Nota: questo descrive il funzionamento di Express nelle versioni 2 e 3. Vedere la fine di questo post per informazioni su Express 4.


staticserve semplicemente file ( risorse statiche ) dal disco. Gli dai un percorso (a volte chiamato punto di montaggio) e serve i file in quella cartella.

Ad esempio, express.static('/var/www')servirebbe i file in quella cartella. Quindi http://server/file.htmlservirebbe una richiesta al tuo server Node /var/www/file.html.

routerè il codice che gestisce i tuoi percorsi. Quando lo fai app.get('/user', function(req, res) { ... });, è routereffettivamente quello che invoca la funzione di callback per elaborare la richiesta.

L'ordine in cui si passano le cose app.usedetermina l'ordine in cui a ciascun middleware viene data la possibilità di elaborare una richiesta. Ad esempio, se hai un file chiamato test.htmlnella tua cartella statica e una route:

app.get('/test.html', function(req, res) {
    res.send('Hello from route handler');
});

Quale viene inviato a un client che richiede http://server/test.html? Qualunque sia il middleware dato per useprimo.

Se lo fai:

app.use(express.static(__dirname + '/public'));
app.use(app.router);

Quindi viene servito il file su disco.

Se lo fai nell'altro modo,

app.use(app.router);
app.use(express.static(__dirname + '/public'));

Quindi il gestore del percorso riceve la richiesta e "Ciao dal gestore del percorso" viene inviato al browser.

Di solito, si desidera posizionare il router sopra il middleware statico in modo che un file con nome accidentale non possa ignorare uno dei percorsi.

Si noti che se non lo fai in modo esplicito useil router, si è implicitamente aggiunto da espresso al punto di definire un percorso (che è il motivo per cui i percorsi ancora lavorato, anche se si ha commentato out app.use(app.router)).


Un commentatore ha sollevato un altro punto sull'ordine statice routerche non avevo affrontato: l'impatto sulle prestazioni complessive della tua app.

Un altro motivo di cui use routersopra staticè quello di ottimizzare le prestazioni. Se lo metti per staticprimo, allora colpirai il disco rigido su ogni singola richiesta per vedere se esiste o meno un file. In un rapido test , ho scoperto che questo sovraccarico ammontava a ~ 1ms su un server senza carico. (È molto probabile che questo numero sia più elevato sotto carico, in cui le richieste competeranno per l'accesso al disco.)

In routerprimo luogo, una richiesta che corrisponde a un percorso non deve mai colpire il disco, risparmiando preziosi millisecondi.

Naturalmente, ci sono modi per mitigare staticil sovraccarico.

L'opzione migliore è mettere tutte le risorse statiche in una cartella specifica. (IE /static) È quindi possibile eseguire il mount staticsu quel percorso in modo che venga eseguito solo quando il percorso inizia con /static:

app.use('/static', express.static(__dirname + '/static'));

In questa situazione, l'avresti messo sopra router. Questo evita di elaborare altri middleware / router se è presente un file, ma ad essere sincero, dubito che otterrai così tanto.

È inoltre possibile utilizzare staticCache, che memorizza nella cache le risorse statiche in memoria in modo da non dover colpire il disco per i file comunemente richiesti. ( Attenzione: staticCache apparentemente verrà rimosso in futuro.)

Tuttavia, non credo che staticCachememorizzi nella cache le risposte negative (quando non esiste un file), quindi non aiuta se lo hai inserito staticCachesopra routersenza montarlo su un percorso.

Come per tutte le domande sulle prestazioni, misura e confronta la tua app del mondo reale (sotto carico) per vedere dove si trovano davvero i colli di bottiglia.


Express 4

Express 4.0 rimuove app.router . Tutto il middleware ( app.use) e le route ( app.getet al) ora vengono elaborati esattamente nell'ordine in cui vengono aggiunti.

In altre parole:

Tutti i metodi di routing verranno aggiunti nell'ordine in cui vengono visualizzati. Si dovrebbe non fare app.use(app.router). Questo elimina il problema più comune con Express.

In altre parole, mescolando app.use()e app[VERB]()funzionerà esattamente nell'ordine in cui sono chiamati.

app.get('/', home);
app.use('/public', require('st')(process.cwd()));
app.get('/users', users.list);
app.post('/users', users.create);

Ulteriori informazioni sulle modifiche in Express 4.


2
L' routerva in un posto. Se, la prima volta che si chiama app.get(o posto altri), non si è ancora used app.router, espresso lo aggiunge per voi.
josh3736,

4
@MikeCauser: No, perché l'overhead dell'accesso al disco (per vedere se esiste un file) è maggiore dell'overhead dell'invocazione della funzione. Nel mio test , quell'overhead ammontava a 1 ms su un server senza carico. È molto probabile che sia più elevato sotto carico, dove le richieste competeranno per l'accesso al disco. Con staticafter router, la domanda sull'altro middleware diventa irrilevante poiché deve essere al di sopra del router.
josh3736,

2
Spiegazione meravigliosa! Grazie mille!
Kirn

3
app.routerviene rimosso nel ramo master corrente, che sarà express-4.0 . Ogni percorso diventa un middleware separato.
yanychar,

3
Un altro chiarimento, mentre lavoro con questo. In Express 4, è possibile assegnare più route a un router, quindi, per utilizzare il router, al router viene assegnato un percorso radice e posizionato nello stack "middleware" tramite app.use (percorso, router). Ciò consente a percorsi correlati di utilizzare ciascuno il proprio router e di assegnare un percorso di base come unità. Se avessi capito meglio, mi sarei offerto di pubblicare un'altra risposta. Ancora una volta, sto ottenendo questo da scotch.io/tutorials/javascript/…
Joe Lapp,

2

Routing significa determinare come un'applicazione risponde a una richiesta client a un particolare endpoint, che è un URI (o percorso) e un metodo di richiesta HTTP specifico (GET, POST e così via). Ogni percorso può avere una o più funzioni del gestore, che vengono eseguite quando il percorso viene abbinato.

In Express 4.0 Router, ci viene data più flessibilità che mai nella definizione dei nostri percorsi.

express.Router () viene utilizzato più volte per definire gruppi di route.

route utilizzata come middleware per elaborare le richieste.

route utilizzata come middleware per convalidare i parametri utilizzando ".param ()".

app.route () utilizzato come collegamento al router per definire più richieste su un percorso

quando stiamo usando app.route (), alleghiamo la nostra app con quel router.

var express = require('express'); //used as middleware
var app = express(); //instance of express.
app.use(app.router);
app.use(express.static(__dirname + '/public')); //All Static like [css,js,images] files are coming from public folder
app.set('views',__dirname + '/views'); //To set Views
app.set('view engine', 'ejs'); //sets View-Engine as ejs
app.engine('html', require('ejs').renderFile); //actually rendering HTML files through EJS. 
app.get('/', function (req, res) {
  res.render('index');  
})
app.get('/test', function (req, res) {
  res.send('test')
})

0

Nella versione Express 4 possiamo facilmente definire i percorsi nel modo seguente:

server.js:

const express = require('express');
const app = express();
const route = require('./route');

app.use('/route', route);
// here we pass in the imported route object

app.listen(3000, () => console.log('Example app listening on port 3000!'));

route.js:

const express = require('express');
const router = express.Router();

router.get('/specialRoute', function (req, res, next) {
     // route is now http://localhost:3000/route/specialRoute
});

router.get('/', function (req, res, next) {
    // route is now http://localhost:3000/route
});

module.exports = router;

In server.jsabbiamo importato l'oggetto router del route.jsfile e lo abbiamo applicato nel modo seguente in server.js:

app.use('/route', route);

Ora tutte le rotte nel route.jshanno il seguente URL di base:

http: // localhost: 3000 / percorso

Perché questo approccio:

Il vantaggio principale di questo approccio è che ora la nostra app è più modulare . Tutti i gestori di percorsi per un determinato percorso ora possono essere inseriti in diversi file, il che rende tutto più gestibile e più facile da trovare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.