Ich versuche, meinem Express-basierten Server eine Authentifizierung hinzuzufügen. Ich bemerke ein seltsames Verhalten des Routings.

Ich habe das Problem auf diesen Express-Code reduziert:

app.get('/', function (req, res) {
    console.log('this is reached first');
    res.send('Hello');
});

app.get('/', function (req, res) {
    console.log('this is not reached');
});

app.get('*', function (req, res) {
    console.log('this is reached');
});

Auf Anfrage '/' wird der 1. Handler aufgerufen. Es gibt eine Antwort und ruft next () nicht auf. Daher bin ich überrascht zu sehen, dass der 3. Handler ('*') auch aufgerufen wird! Eine weitere Überraschung ist, dass die an den 3. Handler übergebene Antwort ('res') nicht mit der an den ersten Handler übergebenen übereinstimmt. (Wenn ich next () vom 1. Handler aus aufrufen würde, würde der 2. Handler mit demselben Antwortobjekt aufgerufen.)

Nun zu meinem eigentlichen Szenario: Ich möchte Anforderungen verarbeiten und die Authentifizierung global überprüfen. Einige Routen sollten jedoch für nicht authentifizierte Benutzer verfügbar bleiben. Ich habe meine Lösung auf Zikes 'Antwort basiert. Ich habe zuerst die "freien" Pfade geroutet. Dann habe ich einen Routen-Handler für alle eingefügt ('*'). Es würde next () aufrufen, wenn der Benutzer authentifiziert ist, oder next (err) auf andere Weise. Es folgen alle "eingeschränkten" Routen. Und schließlich mein eigener Fehlerbehandler mit app.use. Es sieht ungefähr so aus:

app.use(app.router);
app.use(function(err, req, res, next) {
    console.log('An error occurred: ' + err);
    res.send(401, 'Unauthorized');
});

app.get('/', function (req, res) {
    res.send('Hello all');
});

app.all('*', function (req, res, next) {
    if (req.user) {
        next(); // authorized
    } else {
        next(new Error('401')); // unauthorized
    }
});

app.get('/members', function (req, res) {
    res.send('Hello member');
});

Dies funktioniert ziemlich gut und blockiert den Zugriff auf '/ Mitglieder'. Es gibt jedoch einen Fehler: Die Authentifizierungsprüfung und Fehlerbehandlung erfolgt auch beim Zugriff auf den nicht eingeschränkten Pfad ('/'). Nachdem die beabsichtigte Antwort gesendet wurde, versucht der Fehlerbehandler, eine 401-Fehlerantwort zu senden. Letzteres wird nicht gesendet, aber der Code sollte nicht ausgeführt werden.

Ein Nebeneffekt dieses Mechanismus ist auch, dass nicht authentifizierte Benutzer einen 401-Fehler für nicht vorhandene Seiten erhalten. In einigen dieser Fälle möchte ich möglicherweise einen 404 zurückgeben. Aber jetzt drücke ich es einfach ...

Ich habe 2 Fragen:

  1. Ist dieses Verhalten ein Fehler? Sollte der General Handler aufgerufen werden, ohne dass der nächste angerufen wird?
  2. Was wäre eine gute Lösung, um viele, aber nicht alle Routen zu verbinden, ohne sie einzeln markieren zu müssen?
2
oferei 9 Okt. 2012 im 16:07

3 Antworten

Beste Antwort

Bei der ersten Frage vermute ich, dass der Browser mehr als eine Anfrage sendet.

Wenn Sie beispielsweise zu http://localhost:3000/ navigieren, fordert Chrome auch die http://localhost:3000/favicon.ico an

Sie können die Anfrage, die gerade abgefangen wird, wie folgt ausdrucken:

app.get('*', function (req, res) {
    console.log('this is reached');
    console.log('url ' + req.url );
});
2
Hector Correa 9 Okt. 2012 im 13:00
app.get('/', function(req, res, next) {
    console.log('this is reached first.');
    next();
}, function (req, res) {
    console.log('this is reached last.');
    res.send('Hello all');
});

Ich würde es normalerweise so konstruieren:

var auth = require('../modules/authenticate');

app.get('/', auth.requireLogin, routes.index.get);
app.delete('/items/:id', auth.requireLogin, auth.permission.item.delete, routes.item.delete);
1
chovy 9 Okt. 2012 im 17:44

Erstens haben Sie wahrscheinlich zwei Anfragen, wenn Sie nach Hause kommen (favicon.ico). Verwenden Sie app.use(express.logger('dev')), um Anforderungen zu protokollieren. Sie können auch versuchen, diesen Pfad zu blockieren:

app.use('/favicon.ico', function(req, res) {
  console.log('FAVICON')
  res.send(404)
}

Zweitens möchten Sie Ihre Fehler behandeln. Ein guter Weg, um Fehler zu senden:

var err = new Error('this is my error message.')
err.status = 404 // You want to send a "Not Found" page
next(err)

app.use(function(err, req, res, next) {
  var status = err.status
  if (status === 404) res.send(404, 'Page not found.');
  else res.send(500, 'Something went wrong.');
})

Alle behandelten Fehler sollten einen Status haben.

1
Jonathan Ong 10 Okt. 2012 im 06:09