Невозможно установить заголовки после того, как они отправлены клиенту, (но не очевидно, где заголовки переустанавливаются) - PullRequest
0 голосов
/ 16 апреля 2019

Я получаю ошибку Cannot set headers after they are sent to the client после I: 1. входа в систему, 2. выхода из системы и затем 3. входа в систему.

Моя путаница возникает из-за того, что: 1. Я даже не вижу, где код устанавливает заголовки в маршруте 'login' post, и 2. Последовательность команд в '/login' postМаршрут, в котором, по-видимому, возникает ошибка, такой же, как в маршруте '/signup' post, и последний выполняется без проблем.то есть оба имеют назначения на req.session.user, за которыми следует res.redirect('/protected_page');

var express = require('express');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var multer = require('multer');
var upload = multer();
var app = express();

app.set('view engine', 'pug');
app.set('views', __dirname + '/views');

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:true}));
app.use(upload.array());
app.use(cookieParser());
app.use(session({secret: "Shh, it's a secret!"}));
app.use(express.static('public'));

var users = [];

app.get('/signup', function(req, res){
    res.render('signup');
});

app.post('/signup', function(req, res){
    if(!req.body.id || !req.body.password) {
        res.status(400);
        res.send("Invalid details!");
    } else {
        users.filter(function(user) {
            if (user.id === req.body.id) {
                res.render('signup', {
                    message: "User Already Exists! Login or choose another user id"});
            } 
        });
    var newUser = {id: req.body.id, password: req.body.password};
    users.push(newUser);
    req.session.user = newUser;
    res.redirect('/protected_page');
    }
});

function checkSignIn(req,res, next){
    if (req.session.user) {
        next();
    } else {
        var err = new Error("Not logged in!");
        next(err);
    }
}

app.get('/protected_page', checkSignIn, function(req, res){
    res.render('protected_page',{id: req.session.user.id});
})

app.get('/login', function(req,res){
    res.render('login');
})

app.post('/login', function(req,res){
    if (!req.body.id || !req.body.password) {
        res.render('login', {message: "Please enter both id and password!"});
    } else {
        users.filter(function(user){
            if (user.id === req.body.id && user.password === req.body.password) {
                req.session.user = user; //*** PROBLEM SEEMS TO BE HERE ***
                res.redirect('/protected_page'); //*** OR HERE ***
            }
        });
        res.render('login', {message: "Invalid credentials"});
    }
})

app.get('/logout', function(req, res){
    req.session.destroy(function(){
        console.log("user logged out")
    });
    res.redirect('/login');
})

app.use('/protected_page', function(err,req,res,next){
    console.log(err);
    res.redirect('/login');
});

Я вижу, что другие задавали подобные вопросы, но ни один из этих случаев, кажется, не применим к моей ситуации, как в тех других случаях, которые яМожно увидеть, где код пытается записать в заголовок после отправки ответа, но в моем случае я не вижу, где это происходит.Заранее спасибо, если кто-то может помочь в этом!

Ответы [ 3 ]

2 голосов
/ 16 апреля 2019

Если вы присмотритесь к своему маршруту /login, вы увидите следующие строки:

users.filter(function(user){
    if (user.id === req.body.id && user.password === req.body.password) {
        req.session.user = user; //*** PROBLEM SEEMS TO BE HERE ***
        res.redirect('/protected_page'); //*** OR HERE ***
    }
});
res.render('login', {message: "Invalid credentials"});

Как вы уже определили, проблема в одной из обеих строк в if, и вы правы: проблема во второй строке (с redirect).

Причина этого в следующем: перенаправление устанавливает заголовок location, код состояния(301, 302 или 307), отправляет их клиенту и закрывает соединение.К сожалению, вы не выходите из этой функции здесь, так как у вас нет чего-то вроде return здесь.

Это означает, что выполнение продолжается, и происходит вызов res.render, который пытаетсяустановить несколько заголовков и отобразить страницу - что не работает, так как соединение уже закрыто.В зависимости от асинхронной работы, это может произойти и наоборот (я недостаточно внимательно изучил, какой из них стоит первым).Однако вот из-за чего возникают ваши проблемы: вы пытаетесь запустить res.render и res.redirect, и оба устанавливают заголовки, и оба закрывают ваше соединение.

Кроме того, вы используете функцию filterмассивов странным образом, так как он возвращает что-то, поэтому вам лучше сделать:

if (!req.body.id || !req.body.password) {
  res.render('login', {message: "Please enter both id and password!"});
  return;
}

const isLoginCorrect = users.some(function (user) {
  return user.id === req.body.id && user.password === req.body.password;
});

if (isLoginCorrect) {
  req.session.user = user;
  res.redirect('/protected_page');
  return;
}

res.render('login', {message: "Invalid credentials"});

Так как вы на самом деле не заинтересованы в отфильтрованном списке пользователей, это может бытьЛучше всего использовать some, который возвращает только true или false, в зависимости от того, был ли найден элемент в массиве, который соответствует заданной функции предиката.Затем вы можете проверить это логическое значение и решить, как поступить.

1 голос
/ 16 апреля 2019

Ошибка в условной логике. Если следующее условие

if (user.id === req.body.id && user.password === req.body.password)

встречается, обе строки

res.redirect('/protected_page');

и

res.render('login', {message: "Invalid credentials"});
Будет выполнено

, что снова устанавливает заголовок ответа после отправки.

Простое решение: - Поставить условие else.

       if (user.id === req.body.id && user.password === req.body.password) {
            req.session.user = user; //*** PROBLEM SEEMS TO BE HERE ***
            res.redirect('/protected_page'); //*** OR HERE ***
        }
        else {
            res.render('login', {message: "Invalid credentials"});
        }

ПРИМЕЧАНИЕ: - В вашем коде регистрации также есть эта проблема. Попробуйте отправить тот же user.id в следующем запросе.

0 голосов
/ 16 апреля 2019

Попробуйте следующий код:

var express = require('express');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var multer = require('multer');
var upload = multer();
var app = express();

app.set('view engine', 'pug');
app.set('views', __dirname + '/views');

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:true}));
app.use(upload.array());
app.use(cookieParser());
app.use(session({secret: "Shh, it's a secret!"}));
app.use(express.static('public'));

var users = [
    {
        id : "1",
        password : "1"
    }
];

app.get('/signup', function(req, res){
    res.render('signup');
});

app.post('/signup', function(req, res){
    if(!req.body.id || !req.body.password) {
        res.status(400);
        res.send("Invalid details!");
    } else {
        users.filter(function(user) {
            if (user.id === req.body.id) {
                res.render('signup', {
                    message: "User Already Exists! Login or choose another user id"});
            } 
        });
    var newUser = {id: req.body.id, password: req.body.password};
    users.push(newUser);
    req.session.user = newUser;
    res.redirect('/protected_page');
    }
});

function checkSignIn(req,res, next){
    if (req.session.user) {
        next();
    } else {
        var err = new Error("Not logged in!");
        next(err);
    }
}

app.get('/protected_page', checkSignIn, function(req, res){
    res.render('protected_page',{id: req.session.user.id});
})

app.get('/login', function(req,res){
    res.render('login');
})

app.post('/login', function(req,res){
    if (!req.body.id || !req.body.password) {
        res.render('login', {message: "Please enter both id and password!"});
    } else {
        users.filter(function(user){
            if (user.id === req.body.id && user.password === req.body.password) {
                req.session.user = user; //*** PROBLEM SEEMS TO BE HERE ***
                res.redirect('/protected_page'); //*** OR HERE ***
            }
            else {
                res.render('login', {message: "Invalid credentials"});
            }
        });
    }
})

app.get('/logout', function(req, res){
    req.session.destroy(function(){
        console.log("user logged out")
    });
    res.redirect('/login');
})

app.use('/protected_page', function(err,req,res,next){
    console.log(err);
    res.redirect('/login');
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...