Node.js / Express.js - Wie funktioniert app.router?

298

Bevor ich danach frage app.router, sollte ich zumindest erklären, was meiner Meinung nach bei der Arbeit mit Middleware passiert. Um Middleware zu verwenden, ist die zu verwendende Funktion app.use(). Wenn die Middleware ausgeführt wird, wird entweder die nächste Middleware mithilfe von next()aufgerufen oder so eingestellt, dass keine Middleware mehr aufgerufen wird. Das bedeutet, dass die Reihenfolge, in der ich meine Middleware-Aufrufe platziere, wichtig ist, da einige Middleware von anderer Middleware abhängt und einige Middleware gegen Ende möglicherweise nicht einmal aufgerufen wird.

Heute habe ich an meiner Anwendung gearbeitet und meinen Server im Hintergrund laufen lassen. Ich wollte einige Änderungen vornehmen und meine Seite aktualisieren und die Änderungen sofort sehen. Insbesondere habe ich Änderungen an meinem Layout vorgenommen. Ich konnte es nicht zum Laufen bringen, also suchte ich im Stapelüberlauf nach der Antwort und fand diese Frage . Es heißt, um sicherzustellen, dass express.static()das darunter ist require('stylus'). Aber als ich mir den Code dieses OP ansah, sah ich, dass er seinen app.routerAnruf ganz am Ende seiner Middleware-Anrufe hatte, und ich versuchte herauszufinden, warum das so war.

Als ich meine Express.js-Anwendung (Version 3.0.0rc4) erstellt habe, habe ich den Befehl verwendet express app --sessions --css stylusund in meiner app.js-Datei wurde der Code mit meinem app.routerobigen Aufruf express.static()und eingerichtet require('stylus'). Wenn es also bereits so eingerichtet ist, sollte es so bleiben.

Nachdem ich meinen Code neu angeordnet habe, damit ich meine Stylus-Änderungen sehen kann, sieht es folgendermaßen aus:

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');
});

Deshalb habe ich beschlossen, dass der erste Schritt darin besteht, herauszufinden, warum es wichtig ist, überhaupt einen app.routerCode zu haben. Also habe ich es auskommentiert, meine App gestartet und zu navigiert /. Es zeigte meine Indexseite ganz gut. Hmm, vielleicht hat es funktioniert, weil ich das Routing aus meiner Routendatei (route.index) exportiert habe. Als nächstes navigierte ich zu /testund es zeigte Test auf dem Bildschirm an. Haha, OK, ich habe keine Ahnung was app.routermacht. Unabhängig davon, ob es in meinem Code enthalten ist oder nicht, ist mein Routing in Ordnung. Mir fehlt also definitiv etwas.

Hier ist meine Frage:

Könnte jemand bitte erklären, was es app.routertut, wie wichtig es ist und wo ich es in meine Middleware-Aufrufe einfügen soll? Es wäre auch schön, wenn ich eine kurze Erklärung dazu bekommen würde express.static(). Soweit ich das beurteilen kann, express.static()handelt es sich um einen Cache meiner Informationen. Wenn die Anwendung die angeforderte Seite nicht finden kann, überprüft sie den Cache, um festzustellen, ob sie vorhanden ist.

Aust
quelle
18
Vielen Dank, dass Sie diese Frage gestellt haben. Ich habe herumgegoogelt, um diese Antwort zu finden (und die Frage, um sie aufzufordern).
Hari Seldon
8
Das war eine wirklich gut geschriebene Frage, ich habe das Gleiche gegoogelt.
Kirn

Antworten:

329

Hinweis: Hier wird beschrieben, wie Express in den Versionen 2 und 3 funktioniert. Informationen zu Express 4 finden Sie am Ende dieses Beitrags.


staticstellt einfach Dateien ( statische Ressourcen) von der Festplatte bereit. Sie geben ihm einen Pfad (manchmal auch als Einhängepunkt bezeichnet) und er dient den Dateien in diesem Ordner.

Zum Beispiel express.static('/var/www')würde die Dateien in diesem Ordner dienen. Eine Anfrage an Ihren Node-Server für http://server/file.htmlwürde also dienen /var/www/file.html.

routerist Code, der Ihre Routen ausführt. Wenn Sie dies tun app.get('/user', function(req, res) { ... });, routerruft tatsächlich die Rückruffunktion auf, um die Anforderung zu verarbeiten.

Die Reihenfolge, in der Sie die Dinge übergeben, app.usebestimmt die Reihenfolge, in der jede Middleware die Möglichkeit erhält, eine Anforderung zu verarbeiten. Wenn Sie beispielsweise eine Datei test.htmlin Ihrem statischen Ordner und eine Route aufgerufen haben :

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

Welches wird an einen Kunden gesendet, der dies anfordert http://server/test.html? Welche Middleware usezuerst gegeben wird.

Wenn du das tust:

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

Dann wird die Datei auf der Festplatte bereitgestellt.

Wenn Sie es anders machen,

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

Dann erhält der Routen-Handler die Anfrage und "Hallo vom Routen-Handler" wird an den Browser gesendet.

Normalerweise möchten Sie den Router über der statischen Middleware platzieren, damit eine versehentlich benannte Datei eine Ihrer Routen nicht überschreiben kann.

Beachten Sie, dass , wenn sie nicht ausdrücklich usedie routeres implizit durch Express an dem Punkt Sie eine Route definieren hinzugefügt wird (weshalb Ihre Routen noch einmal gearbeitet , obwohl Sie auf Kommentar app.use(app.router)).


Ein Kommentator hat einen weiteren Punkt zur Reihenfolge von staticund routerangesprochen, den ich nicht angesprochen hatte: die Auswirkungen auf die Gesamtleistung Ihrer App.

Ein weiterer Grund für use routeroben staticzu optimieren Leistung. Wenn Sie staticzuerst setzen , drücken Sie bei jeder einzelnen Anforderung auf die Festplatte, um festzustellen, ob eine Datei vorhanden ist oder nicht. In einem schnellen Test stellte ich fest, dass dieser Overhead auf einem entladenen Server ~ 1 ms betrug. (Diese Zahl ist unter Last sehr wahrscheinlich höher, wenn Anforderungen um den Festplattenzugriff konkurrieren.)

Mit routerzunächst eine Anforderung einer Route passend hat nie die Scheibe zu schlagen, spart wertvolle Millisekunden.

Natürlich gibt es Möglichkeiten, den staticOverhead zu verringern .

Am besten legen Sie alle statischen Ressourcen in einem bestimmten Ordner ab. (IE /static) Sie können staticdiesen Pfad dann so bereitstellen, dass er nur ausgeführt wird, wenn der Pfad beginnt mit /static:

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

In dieser Situation würden Sie dies oben setzen router. Dies vermeidet die Verarbeitung anderer Middleware / des Routers, wenn eine Datei vorhanden ist, aber um ehrlich zu sein, bezweifle ich, dass Sie so viel gewinnen werden.

Sie können auch staticCachestatische Ressourcen im Arbeitsspeicher zwischenspeichern, damit Sie nicht auf die Festplatte zugreifen müssen, um häufig angeforderte Dateien zu erhalten. ( Warnung: staticCache wird anscheinend in Zukunft entfernt.)

Ich glaube jedoch nicht, dass staticCachenegative Antworten zwischengespeichert werden (wenn eine Datei nicht vorhanden ist). Daher hilft es nicht, wenn Sie staticCacheoben angegeben haben, routerohne sie an einen Pfad anzuhängen.

Wie bei allen Fragen zur Leistung können Sie Ihre reale App (unter Last) messen und bewerten , um festzustellen , wo die Engpässe tatsächlich liegen.


Express 4

Express 4.0 wird entfernt app.router . Alle Middleware ( app.use) und Routen ( app.getet al.) Werden jetzt genau in der Reihenfolge verarbeitet, in der sie hinzugefügt werden.

Mit anderen Worten:

Alle Routing-Methoden werden in der Reihenfolge hinzugefügt, in der sie angezeigt werden. Das solltest du nicht tun app.use(app.router). Dadurch wird das häufigste Problem mit Express behoben.

Mit anderen Worten, Mischen app.use()und app[VERB]()funktioniert genau in der Reihenfolge, in der sie aufgerufen werden.

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

Lesen Sie mehr über Änderungen in Express 4.

josh3736
quelle
2
Das routergeht an einem Ort. Wenn Sie das erste Mal aufrufen app.get(oder postoder andere), haben Sie noch nicht used app.router, fügt Express es für Sie.
Josh3736
4
@MikeCauser: Nein, da der Overhead des Festplattenzugriffs (um festzustellen, ob eine Datei vorhanden ist oder nicht) größer ist als der Overhead des Funktionsaufrufs. In meinem Test betrug dieser Overhead auf einem entladenen Server 1 ms. Unter Last ist dies sehr wahrscheinlich höher, wenn Anforderungen um den Datenträgerzugriff konkurrieren. Mit staticnach routerwird die Frage nach der anderen Middleware nicht relevant , da es muss über dem Router sein.
Josh3736
2
Wunderbare Erklärung! Ich danke dir sehr!
Kirn
3
app.routerwird entfernt , in dem aktuellen Master - Zweig, der seiner Express-4.0 . Jede Route wird zu einer separaten Middleware.
Yanychar
3
Noch eine Klarstellung, während ich damit arbeite. In Express 4 können einem Router mehrere Routen zugewiesen werden. Um den Router dann zu verwenden, erhält der Router einen Root-Pfad und wird über app.use (Pfad, Router) in den "Middleware" -Stack gestellt. Auf diese Weise können verwandte Routen jeweils ihren eigenen Router verwenden und einen Basispfad als Einheit erhalten. Wenn ich es besser verstehen würde, würde ich anbieten, eine andere Antwort zu posten. Wieder bekomme ich dies von scotch.io/tutorials/javascript/…
Joe Lapp
2

Routing bedeutet zu bestimmen, wie eine Anwendung auf eine Clientanforderung an einen bestimmten Endpunkt reagiert, bei dem es sich um einen URI (oder Pfad) und eine bestimmte HTTP-Anforderungsmethode (GET, POST usw.) handelt. Jede Route kann eine oder mehrere Handlerfunktionen haben, die ausgeführt werden, wenn die Route übereinstimmt.

In Express 4.0 Router erhalten wir mehr Flexibilität als je zuvor bei der Definition unserer Routen.

express.Router () wird mehrmals verwendet, um Gruppen von Routen zu definieren.

Route, die als Middleware zur Verarbeitung von Anforderungen verwendet wird.

Route, die als Middleware zum Überprüfen von Parametern mit ".param ()" verwendet wird.

app.route () wird als Verknüpfung zum Router verwendet, um mehrere Anforderungen auf einer Route zu definieren

Wenn wir app.route () verwenden, hängen wir unsere App an diesen Router an.

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')
})
Parth Raval
quelle
0

In der Express-Version 4 können wir Routen auf folgende Weise einfach definieren:

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 haben server.jswir das Router-Objekt der route.jsDatei importiert und auf folgende Weise angewendet server.js:

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

Jetzt haben alle Routen in route.jsder folgenden Basis-URL:

http: // localhost: 3000 / route

Warum dieser Ansatz:

Der Hauptvorteil dieses Ansatzes besteht darin, dass unsere App jetzt modularer ist . Alle Routenhandler für eine bestimmte Route können jetzt in verschiedenen Dateien abgelegt werden, wodurch alles wartbarer und leichter zu finden ist.

Willem van der Veen
quelle