Остановка цепочки промежуточного программного обеспечения в express4

#node.js #express

#node.js #экспресс

Вопрос:

Ниже приведен код, в который добавлена функция промежуточного программного обеспечения «checkLogin». Промежуточное программное обеспечение eheckLogin должно перенаправлять на страницу входа, если пользователь не вошел в систему. Если пользователь вошел в систему, он должен отобразить запрошенную страницу.

 var express = require('express');
var router = express.Router();
var mongoUri = 'mongodb://localhost/mydb';
var MongoClient = require('mongodb').MongoClient;

function mongoDBConnect(req, res, next) {
    MongoClient.connect('mongodb://localhost/gadda_db', function(err, db) {
    if(!err) {
        req.db = db;
        next();
    } else {
        res.send('unable to connect to mongodb: err = '   err);
    }
    });
};

function checkLogin(req, res, next) {
    if (req.loggedin) {
    next();
    return;
    }

    if (req.loggedin amp;amp; req.url === '/login') {
    res.redirect('http://'   'localhost:3000'   '/game/my_game'); 
    return;
    }

    if (!req.loggedin amp;amp; req.url === '/login') {
    next();
    return;
    }
    req.db.collection('game_users', function (err, collection) {
        if (err) {
        res.send("error while reading game_users: err "   err);
    }
        collection.findOne({user: req.cookies.user, password: req.cookies.password},
               function (err, user) {
                   if (err) {
                   res.send("error here");
                   return;
                   }
                   req.loggedin = true;
                   next();
                   return;
               });
    });

    res.redirect('login');
    return;
};

router.use(mongoDBConnect);
router.use(checkLogin);

router.get('/', function(req, res) {
    res.redirect('http://'   'localhost:3000'   '/game/my_game');
});

router.get('/login', function(req, res) {
    res.render('gadda_login', {title: 'gadda', error: ''});
});
  

При отправке запроса на localhost:3000/gadda на сервере выводится следующее сообщение об ошибке

Ошибка GET /gadda/ 302 34ms — 66b: не удается установить заголовки после их отправки. при ответе сервера.Выходное сообщение.setHeader (http.js:691:11) в ServerResponse.res.set.res.header (/home/hhk/src/nodejs_projects/gadda_v2/node_modules/express/lib/response.js:551:10) в ServerResponse.res.send (/home/hhk/src/nodejs_projects/gadda_v2/ node_modules/express/lib/response.js:132:12) в fn (/home/hhk/src/nodejs_projects/gadda_v2/node_modules/express/lib/response.js:778:10) в View.exports.RenderFile [как движок] (/home/hhk/src/nodejs_projects/gadda_v2/node_modules/ejs/lib/ejs.js:318:3) в View. визуализация (/home/hhk/src/nodejs_projects/gadda_v2/node_modules/express/lib/view.js: 76:8) в Function.app.render (/home/hhk/src/nodejs_projects/gadda_v2/node_modules/express/lib/application.js:519:10) в ServerResponse.res.render (/home/hhk/src/nodejs_projects/gadda_v2/ node_modules/express/lib/response.js:782:7) в Layer.module.exports [как дескриптор] (/home/hhk/src/nodejs_projects/gadda_v2/app.js:54:9) в trim_prefix (/home/hhk/src/nodejs_projects/gadda_v2/node_modules/express/lib/router/index.js:252:17) router.get /login ПОЛУЧИТЬ /gadda/login 200 11ms — 546b ПОЛУЧИТЬ /таблицы стилей/style.css 200 за 4 мс — 110b

Комментарии:

1. Отправляется ли ваша форма входа на тот же URL (/login)? Если это так, то логично, возможно, пропустить проверку, чтобы увидеть, вошли ли они в систему (в вызове базы данных) путем сопоставления с предыдущим оператором if ( req.url === '/login' ). Кроме того, вы перенаправляетесь на login ( res.redirect('login'); ), прежде чем разрешить обратный вызов вашей базы данных.

2. @dylants: Публикация выполняется по URL ‘/users/new’. router.post(‘/user/new’, функция(запрос, разрешение) {….}). Проблема, по-видимому, заключается в том, что после res.redirect(‘login’) в checkLogin снова выполняется req.redirect(…) в router.get(‘/’, fun(…)). Извлеченный урок заключается в том, что невозможно избежать выполнения функции в router.get(‘/’, function()..{}), что бы ни делалось в промежуточном программном обеспечении. Хотя это может быть интуитивно понятным для многих, но для меня это очень ново. Я искал router.get fns как часть цепочки промежуточного программного обеспечения, ожидая, что она отключится от какой-либо функции промежуточного программного обеспечения.

3. Можно избежать вызова маршрута через промежуточное программное обеспечение. Я думаю, это может быть связано с тем, как написана checkLogin функция. Я попытался объяснить в приведенном ниже ответе, пожалуйста, дайте мне знать, если это имеет смысл.

Ответ №1:

Из кода, который вы вставили выше, следует, что вы перенаправляете на «login», прежде чем ждать возврата поиска по базе данных. Попробуйте провести рефакторинг вашей checkLogin функции следующим образом:

 function checkLogin(req, res, next) {
    if (req.loggedin) {
        if (req.url === '/login') {
            res.redirect('http://'   'localhost:3000'   '/game/my_game');
            return;
        }
        next();
        return;
    }

    if (!req.loggedin amp;amp; req.url === '/login') {
        next();
        return;
    }

    req.db.collection('game_users', function(err, collection) {
        if (err) {
            res.send("error while reading game_users: err "   err);
            return;
        }

        collection.findOne({
            user: req.cookies.user,
            password: req.cookies.password
        }, function(err, user) {
            if (err) {
                res.send("error here");
                return;
            }

            if (user) {
                req.loggedin = true;
                next();
                return;
            } else {
                res.redirect('/login');
                return;
            }
        });
    });
}
  

Я переместил перенаправление в / login, чтобы оно выполнялось только тогда, когда вызов базы данных возвращается без соответствующего пользователя. Это означает, что вы выполнили поиск, но не нашли ни одного совпадения, а это означает, что предоставленные пользователь и пароль (содержащиеся в файлах cookie?) неверны.

Смысл здесь в том, чтобы выполнить res.send или res.redirect только один раз, и если мы должны не делать это в промежуточном программном обеспечении, то просто вызываем next() . Если вы не вызовете next() ваш код, он не попадет в код маршрута.

Однако здесь будьте осторожны, поскольку этот код не позволит никаким запросам попасть по назначению, если это не аутентифицированный запрос. Сюда входят такие вещи, как значок или ресурсы.

Комментарии:

1. Я ожидал, что collection.findOne() не вызовет обратный вызов, если пользователь не существует в базе данных. Это и стало причиной проблемы. Спасибо.