将标头发送给客户端后,无法设置标头(但在重新设置标头的地方不明显)

时间:2019-04-16 04:26:28

标签: node.js express

在我执行以下操作后出现Cannot set headers after they are sent to the client错误: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 个答案:

答案 0 :(得分:2)

如果您仔细查看自己的/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标头,状态代码(301302307),并将其发送到客户端并关闭连接。不幸的是,您没有在这里退出功能,因为这里没有return之类的东西。

这意味着继续执行,并且对res.render的调用发生,该调用试图设置一些标题并呈现一个页面-由于连接已关闭,该页面不起作用。取决于异步的东西,它也可能以相反的方式发生(我没有足够仔细地跟进来检查哪个先出现)。但是,这是您出现问题的根源:您尝试运行res.renderres.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,它仅返回truefalse,具体取决于是否在与给定谓词函数匹配的数组中找到了item。然后,您可以检查此布尔值,并确定如何继续。

答案 1 :(得分:1)

错误在于条件逻辑中。如果满足以下条件

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。

答案 2 :(得分:0)

尝试以下代码:

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');
});