Was bedeuten Middleware und App.use in Expressjs?

228

Fast jede Express-App, die ich sehe, enthält eine app.useAnweisung für Middleware, aber ich habe keine klare, präzise Erklärung dafür gefunden, was Middleware tatsächlich ist und was die app.useAnweisung tut. Sogar die Expressdokumente selbst sind diesbezüglich etwas vage. Können Sie mir diese Konzepte bitte erklären?

iZ.
quelle
3
ähnliche Frage als Referenz (obwohl diese früher erstellt wurde): stackoverflow.com/questions/11321635/…
ericsoco
43
^ Ha! Diese beiden Fragen verweisen in den Kommentaren aufeinander.
Julian H. Lam
17
Es ist also eine kreisförmige Referenz.
Steve K
6
Express.js Middleware entmystifiziert Ein großartiger Blog-Beitrag zum Thema. Dies wurde hier schon einmal kopiert, was natürlich ein Plagiat ist, aber der ursprüngliche Beitrag ist immer noch sehr hilfreich, deshalb hinterlasse ich hier einen Link.
Totymedli
1
Ich habe einen Artikel über die Middleware von express.j geschrieben. Hier ist der Link: nodexplained.com/blog-detail/2017/12/31/…
shrawan_lakhe

Antworten:

111

Middleware

Ich bin auf halbem Weg, das Konzept der Middleware in einem neuen Projekt zu trennen.

Mit Middleware können Sie einen Stapel von Aktionen definieren, die Sie durchlaufen sollen. Express-Server selbst sind ein Stapel von Middleware.

// express
var app = express();
// middleware
var stack = middleware();

Anschließend können Sie dem Middleware-Stack durch Aufrufen Ebenen hinzufügen .use

// express
app.use(express.static(..));
// middleware
stack.use(function(data, next) {
  next();
});

Eine Schicht im Middleware-Stack ist eine Funktion, die n Parameter (2 für Express, req& res) und eine nextFunktion akzeptiert.

Middleware erwartet, dass die Schicht einige Berechnungen durchführt, die Parameter erweitert und dann aufruft next.

Ein Stapel macht nichts, wenn Sie nicht damit umgehen. Express verarbeitet den Stapel jedes Mal, wenn eine eingehende HTTP-Anforderung auf dem Server abgefangen wird. Mit Middleware behandeln Sie den Stack manuell.

// express, you need to do nothing
// middleware
stack.handle(someData);

Ein vollständigeres Beispiel:

var middleware = require("../src/middleware.js");

var stack = middleware(function(data, next) {
    data.foo = data.data*2;
    next();
}, function(data, next) {
    setTimeout(function() {
        data.async = true;
        next();
    }, 100)
}, function(data) {
    console.log(data);
});

stack.handle({
    "data": 42
})

In Express-Begriffen definieren Sie einfach einen Stapel von Operationen, die Express für jede eingehende HTTP-Anforderung verarbeiten soll.

In Bezug auf Express (anstatt Verbindung) verfügen Sie über globale Middleware und routenspezifische Middleware. Dies bedeutet, dass Sie einen Middleware-Stack an alle eingehenden HTTP-Anforderungen anhängen oder ihn nur an HTTP-Anforderungen anhängen können, die mit einer bestimmten Route interagieren.

Erweiterte Beispiele für Express- und Middleware:

// middleware 

var stack = middleware(function(req, res, next) {
    users.getAll(function(err, users) {
        if (err) next(err);
        req.users = users;
        next();  
    });
}, function(req, res, next) {
    posts.getAll(function(err, posts) {
        if (err) next(err);
        req.posts = posts;
        next();
    })
}, function(req, res, next) {
    req.posts.forEach(function(post) {
        post.user = req.users[post.userId];
    });

    res.render("blog/posts", {
        "posts": req.posts
    });
});

var app = express.createServer();

app.get("/posts", function(req, res) {
   stack.handle(req, res); 
});

// express

var app = express.createServer();

app.get("/posts", [
    function(req, res, next) {
        users.getAll(function(err, users) {
            if (err) next(err);
            req.users = users;
            next();  
        });
    }, function(req, res, next) {
        posts.getAll(function(err, posts) {
            if (err) next(err);
            req.posts = posts;
            next();
        })
    }, function(req, res, next) {
        req.posts.forEach(function(post) {
            post.user = req.users[post.userId];
        });

        res.render("blog/posts", {
            "posts": req.posts
        });
    }
], function(req, res) {
   stack.handle(req, res); 
});
Raynos
quelle
4
Hmm ... ist Middleware in diesem Fall Ihre eigene Bibliothek oder ein Teil von Express?
iZ.
5
Cool. Ich bin immer noch ein bisschen verwirrt von der app.use()Syntax. Was ist der tatsächliche Rückgabewert der Middleware und was macht usesie damit?
iZ.
9
@iZ use fügt es einem Stapel hinzu. Dann geht jede einzelne Anfrage durch den Stapel.
Raynos
7
@ Raynos, der Link zu Ihrem Projekt "Middleware" ist unterbrochen.
Lee
1
@ Raynos, aber ich sehe, dass Middleware immer noch in Express verwendet wird? Was meinst du damit, es ist nuklear?
Timo Huovinen
60

Nach der Vereinfachung kann ein Webserver als eine Funktion angesehen werden, die eine Anforderung aufnimmt und eine Antwort ausgibt. Wenn Sie also einen Webserver als Funktion betrachten, können Sie ihn in mehrere Teile organisieren und in kleinere Funktionen aufteilen, sodass die Zusammensetzung der ursprünglichen Funktion entspricht.

Middlewares sind die kleineren Funktionen, die Sie mit anderen zusammenstellen können, und der offensichtliche Vorteil besteht darin, dass Sie sie wiederverwenden können.

Barum Rho
quelle
33

Ich füge eine späte Antwort hinzu, um etwas hinzuzufügen, das in den vorherigen Antworten nicht erwähnt wurde.

Inzwischen sollte klar sein, dass Middleware zwischen der Client-Anfrage und der Server-Antwort ausgeführt wird . Die am häufigsten benötigten Middleware-Funktionen sind Fehlerverwaltung, Datenbankinteraktion, Abrufen von Informationen aus statischen Dateien oder anderen Ressourcen. Um auf dem Middleware-Stack zu wechseln, muss der nächste Rückruf aufgerufen werden. Sie können ihn am Ende der Middleware-Funktion sehen, um zum nächsten Schritt im Ablauf zu gelangen.

Sie können den app.useAnsatz verwenden und einen Fluss wie folgt haben :

var express = require('express'),
    app = express.createServer(),                                                                                                                                                 
    port = 1337;

function middleHandler(req, res, next) {
    console.log("execute middle ware");
    next();
}

app.use(function (req, res, next) {
    console.log("first middle ware");                                                                                                             
    next();
});

app.use(function (req, res, next) {
    console.log("second middle ware");                                                                                                             
    next();
});

app.get('/', middleHandler, function (req, res) {
    console.log("end middleware function");
    res.send("page render finished");
});

app.listen(port);
console.log('start server');

Sie können aber auch einen anderen Ansatz verwenden und jede Middleware als Funktionsargumente übergeben. Hier ist ein Beispiel von der MooTools Nodejs-Website, auf der Midleware den Twitter-, Github- und Blog-Flow erhält, bevor der responsean den Client zurückgesendet wird. Beachten Sie, wie die Funktionen als Argumente in übergeben werden app.get('/', githubEvents, twitter, getLatestBlog, function(req, res){. Die Verwendung app.getwird nur für GET-Anforderungen app.useaufgerufen , wird für alle Anforderungen aufgerufen.

// github, twitter & blog feeds
var githubEvents = require('./middleware/githubEvents')({
    org: 'mootools'
});
var twitter = require('./middleware/twitter')();
var blogData = require('./blog/data');
function getLatestBlog(req, res, next){
    blogData.get(function(err, blog) {
        if (err) next(err);
        res.locals.lastBlogPost = blog.posts[0];
        next();
    });
}

// home
app.get('/', githubEvents, twitter, getLatestBlog, function(req, res){
    res.render('index', {
        title: 'MooTools',
        site: 'mootools',
        lastBlogPost: res.locals.lastBlogPost,
        tweetFeed: res.locals.twitter
    });
});
Sergio
quelle
2
Ich habe nach einer Antwort gesucht, ob Express.js die routenbasierte (NICHT routerbasierte) Middleware-Bereitstellung unterstützt. Es scheint, dass Sie es in Ihrer Antwort gezeigt haben.
Selçuk
Können Sie Ihr obiges Beispiel erklären? Wie können Sie so viele Funktionen an app.get (...) übergeben und in welcher Reihenfolge heißen sie?
Tanner Summers
2
Hallo @TannerSummers, die .get()Methode akzeptiert drei Arten von Argumenten: das erste, das letzte und das mittlere. Intern erkennt es, ob mehr Argumente als 2 vorhanden sind, und verwendet diese (die mittleren) als Middleware-Funktionen und ruft sie von links nach rechts auf.
Sergio
22

expressjs guide hat eine ziemlich gute Antwort auf Ihre Frage. Ich empfehle Ihnen dringend, diese zu lesen. Ich poste einen kurzen Ausschnitt des Guides. Der Guide ist ziemlich gut.

Schreiben von Middleware zur Verwendung in Express-Apps

Überblick

Middleware- Funktionen sind Funktionen, die Zugriff auf das Anforderungsobjekt ( req ), das Antwortobjekt ( res ) und die nächste Funktion im Anforderungs- / Antwortzyklus der Anwendung haben. Die nächste Funktion ist eine Funktion im Express-Router, die beim Aufrufen die Middleware ausführt, die der aktuellen Middleware folgt.

Middleware-Funktionen können die folgenden Aufgaben ausführen:

  • Führen Sie einen beliebigen Code aus.
  • Nehmen Sie Änderungen an der Anforderung und den Antwortobjekten vor.
  • Beenden Sie den Anforderungs- / Antwortzyklus.
  • Rufen Sie die nächste Middleware im Stack auf.

Wenn die aktuelle Middleware-Funktion den Anforderungs- / Antwortzyklus nicht beendet, muss next () aufgerufen werden , um die Steuerung an die nächste Middleware-Funktion zu übergeben. Andernfalls bleibt die Anfrage hängen.

Geben Sie hier die Bildbeschreibung ein

Beispiel

Hier ist ein Beispiel für eine einfache Express-Anwendung „Hello World“. Der Rest dieses Artikels definiert und fügt der Anwendung zwei Middleware-Funktionen hinzu: eine mit dem Namen myLogger , die eine einfache Protokollnachricht druckt, und eine mit dem Namen requestTime 1 , die den Zeitstempel der HTTP-Anforderung anzeigt.

var express = require('express')
var app = express()

app.get('/', function (req, res) {
  res.send('Hello World!')
})

app.listen(3000)   

Middleware-Funktion myLogger

Hier ist ein einfaches Beispiel für eine Middleware-Funktion namens "myLogger". Diese Funktion druckt nur "LOGGED", wenn eine Anfrage an die App durch sie geht. Die Middleware-Funktion ist einer Variablen namens myLogger zugeordnet.

var myLogger = function (req, res, next) {
  console.log('LOGGED')
  next()
}

Beachten Sie den obigen Aufruf von next () . Durch Aufrufen dieser Funktion wird die nächste Middleware-Funktion in der App aufgerufen. Die next () -Funktion ist kein Teil der Node.js- oder Express-API, sondern das dritte Argument, das an die Middleware-Funktion übergeben wird. Die next () -Funktion kann beliebig benannt werden, wird jedoch konventionell immer als "next" bezeichnet. Verwenden Sie immer diese Konvention, um Verwirrung zu vermeiden.

Rufen Sie zum Laden der Middleware-Funktion app.use () auf und geben Sie die Middleware-Funktion an. Der folgende Code lädt beispielsweise die myLogger- Middleware-Funktion vor der Route zum Stammpfad (/).

var express = require('express')
var app = express()

var myLogger = function (req, res, next) {
  console.log('LOGGED')
  next()
}

app.use(myLogger)

app.get('/', function (req, res) {
  res.send('Hello World!')
})

app.listen(3000)

Jedes Mal, wenn die App eine Anfrage erhält, druckt sie die Nachricht „LOGGED“ an das Terminal.

Die Reihenfolge des Ladens der Middleware ist wichtig: Middleware-Funktionen, die zuerst geladen werden, werden ebenfalls zuerst ausgeführt.

Wenn myLogger nach der Route zum Stammpfad geladen wird, erreicht die Anforderung diese nie und die App druckt nicht "LOGGED", da der Routenhandler des Stammpfads den Anforderungs- / Antwortzyklus beendet.

Die Middleware-Funktion myLogger druckt einfach eine Nachricht und leitet die Anforderung durch Aufrufen der next () -Funktion an die nächste Middleware-Funktion im Stapel weiter .


  1. Dieser Beitrag enthält nur die myLogger-Middleware. Weitere Beiträge finden Sie im Original-Expressjs-Handbuch hier .

Suraj Jain
quelle
1
Sehr schöne Erklärung.
Drumbeg
Es ist auf der Express-Website hier expressjs.com/en/guide/writing-middleware.html verfügbar , es ist wirklich gut. Ich frage mich, warum es bisher niemand erwähnt hat.
Suraj Jain
2
Schön. Es ist die klarste Erklärung, die ich hier gesehen habe und ja, seltsam, dass niemand darauf verwiesen hat!
Drumbeg
1
Schön erklärt
Rehan Shikkalgar
Die Reihenfolge des Ladens der Middleware ist wichtig: Middleware-Funktionen, die zuerst geladen werden, werden ebenfalls zuerst ausgeführt. : Dies ist ein so wichtiger Hinweis. Keine andere Antwort erwähnt dies. Für einen Anfänger, der nur an Python gearbeitet hat, ist dies äußerst wichtig, da diese Dinge möglicherweise nie angetroffen wurden.
Tessaracter
11

===== Sehr sehr einfache Erklärung =====

Middlewares werden häufig im Kontext des Express.js-Frameworks verwendet und sind ein grundlegendes Konzept für node.js. Kurz gesagt, es ist im Grunde eine Funktion, die Zugriff auf die Anforderungs- und Antwortobjekte Ihrer Anwendung hat. Die Art und Weise, wie ich darüber nachdenken möchte, ist eine Reihe von "Überprüfungen / Vorabprüfungen", die die Anforderung durchläuft, bevor sie von der Anwendung verarbeitet wird. Zum Beispiel wäre Middlewares eine gute Lösung, um festzustellen, ob die Anforderung authentifiziert ist, bevor sie zur Anwendung weitergeleitet wird, und um die Anmeldeseite zurückzugeben, wenn die Anforderung nicht authentifiziert ist, oder um jede Anforderung zu protokollieren. Es sind viele Middlewares von Drittanbietern verfügbar, die eine Vielzahl von Funktionen ermöglichen.

Einfaches Middleware-Beispiel:

var app = express();
app.use(function(req,res,next)){
    console.log("Request URL - "req.url);
    next();
}

Der obige Code würde für jede eingehende Anforderung ausgeführt und die Anforderungs-URL protokollieren. Die next () -Methode ermöglicht es dem Programm im Wesentlichen, fortzufahren. Wenn die next () -Funktion nicht aufgerufen wird, würde das Programm nicht weiter fortfahren und bei der Ausführung der Middleware anhalten.

Ein paar Middleware-Fallstricke:

  1. Die Reihenfolge der Middlewares in Ihrer Anwendung ist wichtig, da die Anforderung jede in einer sequentiellen Reihenfolge durchläuft.
  2. Wenn Sie vergessen, die next () -Methode in Ihrer Middleware-Funktion aufzurufen, kann die Verarbeitung Ihrer Anfrage angehalten werden.
  3. Jede Änderung der Objekte req und res in der Middleware-Funktion würde die Änderung anderen Teilen der Anwendung zur Verfügung stellen, die req und res verwenden
Vaibhav Bacchav
quelle
1
Vielen Dank! Dies ist die bisher beste Erklärung, um dies zu verstehen. Eine Frage, ich lese einen Code mit Middleware und er ruft next()aber nicht auf return next(). Was ist der Unterschied?
KansaiRobot
Vielen Dank Freund für freundliche Worte ... wir tun, next()weil wir wollen, dass die nächste Middleware aufgerufen wird, ich denke nicht next()oder return next()sollte einen Unterschied machen! Trotzdem kommt es darauf an, wie der Code lautet ...
Vaibhav Bacchav
7

Middlewares sind Funktionen, die in der Mitte ausgeführt werden, nachdem die Eingabe / Quelle eine Ausgabe erzeugt, die die endgültige Ausgabe sein oder von der nächsten Middleware verwendet werden kann, bis der Zyklus abgeschlossen ist.

Es ist wie ein Produkt, das eine Montagelinie durchläuft, wo es im Laufe der Zeit geändert wird, bis es fertiggestellt, bewertet oder abgelehnt wird.

Eine Middleware erwartet, dass ein Wert bearbeitet wird (dh Parameterwerte), und basierend auf einer Logik ruft die Middleware die nächste Middleware auf oder nicht oder sendet eine Antwort an den Client zurück.

Wenn Sie das Middleware-Konzept immer noch nicht verstehen können, ähnelt es dem Decorator oder der Chain of Command-Muster.

naz
quelle
5

Middleware ist eine Teilmenge verketteter Funktionen, die von der Express js-Routing-Schicht aufgerufen werden, bevor der benutzerdefinierte Handler aufgerufen wird. Middleware-Funktionen haben vollen Zugriff auf die Anforderungs- und Antwortobjekte und können beide ändern.

Die Middleware-Kette wird immer in der genauen Reihenfolge aufgerufen, in der sie definiert wurde. Daher ist es wichtig, dass Sie genau wissen, was eine bestimmte Middleware tut.
Sobald eine Middleware-Funktion beendet ist, ruft sie die nächste Funktion in der Kette auf, indem sie das nächste Argument als Funktion aufruft.
Nachdem die gesamte Kette ausgeführt wurde, wird der Benutzeranforderungshandler aufgerufen.

Rishabh Dev
quelle
1

Halte die Dinge einfach, Mann!

Hinweis: Die Antwort bezieht sich auf die in ExpressJS integrierten Middlware-Fälle. Es gibt jedoch unterschiedliche Definitionen und Anwendungsfälle für Middleware.

Aus meiner Sicht fungiert Middleware als Dienstprogramm oder Hilfsfunktion, aber ihre Aktivierung und Verwendung ist völlig optional, indem sie den app.use('path', /* define or use builtin middleware */)Code verwendet, der nicht von uns geschrieben werden soll, um sehr häufige Aufgaben zu erledigen, die für jede HTTP-Anforderung unseres Clients erforderlich sind B. die Verarbeitung von Cookies, CSRF-Token und ..., die in den meisten Anwendungen sehr häufig vorkommen, sodass Middleware uns dabei helfen kann, diese alle für jede HTTP-Anforderung unseres Clients in einem Stapel, einer Reihenfolge oder einer Reihenfolge von Vorgängen auszuführen, und dann das Ergebnis des Prozesses als eine einzelne Einheit der Client-Anfrage .

Beispiel:

Das Akzeptieren von Kundenanfragen und das Bereitstellen von Rückantworten gemäß ihren Anforderungen ist die Natur der Webservertechnologie.

Stellen Sie sich vor, wir antworten nur mit "Hallo Welt!" Der Text für eine GET HTTP-Anfrage an den Root-URI unseres Webservers ist ein sehr einfaches Szenario und benötigt nichts anderes. Stattdessen überprüfen wir den aktuell angemeldeten Benutzer und antworten dann mit "Hallo, Benutzername!" benötigt etwas mehr als üblich In diesem Fall benötigen wir eine Middleware, um alle Clientanforderungs-Metadaten zu verarbeiten und uns die aus der Clientanforderung entnommenen Identifikationsinformationen bereitzustellen. Anschließend können wir unseren aktuellen Benutzer anhand dieser Informationen eindeutig identifizieren und können auf ihn antworten / sie mit einigen verwandten Daten.

Hoffe es hilft jemandem!

MNR
quelle
-1

Kurz gesagt, wenn ich es so erklären möchte, lerne ich dies aus dem Traversymedia Youtube Channel Express Crash Kurs.
ok also Middleware ist eine Funktion, die ausgeführt wird, nachdem Sie Ihre Route wie folgt aufgerufen haben.

var logger = function(req, res, next){
   console.log('logging...');
   next();
}

app.use(logger);

Diese Logger-Funktion wird jedes Mal ausgeführt, wenn Sie Ihre Seite aktualisieren. Dies bedeutet, dass Sie alles darin schreiben können, was Sie tun müssen, nachdem Ihre Seite einen API-Aufruf für eine Operation ausgeführt hat. Setzen Sie die Dinge im Grunde genommen zurück. und stellen Sie diese Middleware vor Ihre Routenfunktion. Die Reihenfolge der Middleware ist wirklich wichtig oder funktioniert nicht

Akshay Vinchurkar
quelle