#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() не вызовет обратный вызов, если пользователь не существует в базе данных. Это и стало причиной проблемы. Спасибо.