Error: Can't set headers after they are sent using passportjs/Express
Error: Can't set headers after they are sent using passportjs/Express
有问题的错误
Error: Can't set headers after they are sent.
server.js
// set up ======================================================================
var express = require('express')
, app = express()
, cookieParser = require('cookie-parser')
, bodyParser = require('body-parser')
, expressSession = require('express-session')
, server = require('http').createServer(app)
, passport = require('passport')
, local = require('passport-local').Strategy
, md5 = require('md5')
, util = require('util')
, flash = require('connect-flash')
, port = 80
, url = require('url')
, db = require('./db');
// optimization ================================================================
var compress = require('compression');
app.use(compress());
// configuration ===============================================================
app.use(express.static('public'));
app.use(cookieParser());
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.use(expressSession({
secret: 'key',
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
// passport ====================================================================
passport.use(new local(
function(username, password, done) {
// asynchronous verification, for effect...
process.nextTick(function () {
db.findUserByName(username, function (err, user) {
if (err) { done(err); }
if (!user) { done(null, false, {message: 'Unknown user: ' + username})}
if (md5(password) == user.password) {
done(null, user);
} else {
done(null, false, {message: 'Invalid username or password'});
}
});
});
}
));
passport.serializeUser(function(user, done) {
done(null, user.uuid);
});
passport.deserializeUser(function (id, done) {
db.findUserByUUID(id, done);
});
// routes ======================================================================
require('./routes')(app, passport);
// launch ======================================================================
server.listen(port, function(){
console.log('server started');
});
routes.js
var flash = require('connect-flash');
module.exports = function(app, passport) {
app.get('/', function(req, res) {
res.render('index', { num: 0, logged: false });
});
app.get('/login', function (req, res) {
if (typeof req.user !== 'undefined') {
// User is logged in.
res.redirect('/');
} else {
req.user = false;
var message = req.flash('error');
if (message.length < 1) {
message = false;
}
res.render('login', { logged: false, message: message });
}
});
app.post('/login',
passport.authenticate('local', {
failureRedirect: '/login',
failureFlash: true
}),
function(req, res) {
res.redirect('/');
}
);
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
};
db.js
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var ObjectId = require('mongodb').ObjectID;
var url = 'mongodb://localhost:27017/db';
exports.findUserByName = function (username, callback) {
MongoClient.connect(url, function(err, db) {
var cursor = db.collection('players').find( { "name": username } );
cursor.each(function(err, doc) {
if (doc != null) {
console.log('YES');
callback(false, doc)
} else {
console.log('NO');
callback(false, null);
}
db.close();
});
});
};
var findUserByUUID = function(uuid, db, callback) {
var cursor = db.collection('players').find( { "uuid": uuid } );
cursor.each(function(err, doc) {
assert.equal(err, null);
if (doc != null) {
callback(false, doc)
} else {
callback(false, null);
}
});
};
exports.findUserByUUID = function (uuid, callback) {
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
findUserByUUID(uuid, db, function(err, data) {
callback(err, data);
db.close();
});
});
};
我知道我调用了 done() 两次,但是什么时候?我找不到它。
估计是路由的问题,不知道是哪里。
在您的 passport.use()
处理程序中,每次调用 done()
时,您都需要 return
以便它之后的代码不会也被执行。
现在您有一系列 if
语句,每个语句都可以调用 done()
,但它们不是 if/else
语句,因此您要测试的条件不止一个满足,因此 done()
可以被多次调用。
例如,更改为:
if (!user) { done(null, false, {message: 'Unknown user: ' + username})}
对此:
if (!user) {
done(null, false, {message: 'Unknown user: ' + username});
return;
}
并且,改变这个:
if (err) { done(err); }
对此:
if (err) {
done(err);
return;
}
或者,您可以将所有内容都变成 if/else if/else if/else
,这样只有一个分支可以执行。当您的多个 if
语句满足其条件然后被执行时,就会出现问题。
现在,您的 findUserByName()
在 cursor.each()
中调用其回调,因此它可以多次调用它,然后您会多次调用 done()
。
有问题的错误
Error: Can't set headers after they are sent.
server.js
// set up ======================================================================
var express = require('express')
, app = express()
, cookieParser = require('cookie-parser')
, bodyParser = require('body-parser')
, expressSession = require('express-session')
, server = require('http').createServer(app)
, passport = require('passport')
, local = require('passport-local').Strategy
, md5 = require('md5')
, util = require('util')
, flash = require('connect-flash')
, port = 80
, url = require('url')
, db = require('./db');
// optimization ================================================================
var compress = require('compression');
app.use(compress());
// configuration ===============================================================
app.use(express.static('public'));
app.use(cookieParser());
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.use(expressSession({
secret: 'key',
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
// passport ====================================================================
passport.use(new local(
function(username, password, done) {
// asynchronous verification, for effect...
process.nextTick(function () {
db.findUserByName(username, function (err, user) {
if (err) { done(err); }
if (!user) { done(null, false, {message: 'Unknown user: ' + username})}
if (md5(password) == user.password) {
done(null, user);
} else {
done(null, false, {message: 'Invalid username or password'});
}
});
});
}
));
passport.serializeUser(function(user, done) {
done(null, user.uuid);
});
passport.deserializeUser(function (id, done) {
db.findUserByUUID(id, done);
});
// routes ======================================================================
require('./routes')(app, passport);
// launch ======================================================================
server.listen(port, function(){
console.log('server started');
});
routes.js
var flash = require('connect-flash');
module.exports = function(app, passport) {
app.get('/', function(req, res) {
res.render('index', { num: 0, logged: false });
});
app.get('/login', function (req, res) {
if (typeof req.user !== 'undefined') {
// User is logged in.
res.redirect('/');
} else {
req.user = false;
var message = req.flash('error');
if (message.length < 1) {
message = false;
}
res.render('login', { logged: false, message: message });
}
});
app.post('/login',
passport.authenticate('local', {
failureRedirect: '/login',
failureFlash: true
}),
function(req, res) {
res.redirect('/');
}
);
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
};
db.js
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var ObjectId = require('mongodb').ObjectID;
var url = 'mongodb://localhost:27017/db';
exports.findUserByName = function (username, callback) {
MongoClient.connect(url, function(err, db) {
var cursor = db.collection('players').find( { "name": username } );
cursor.each(function(err, doc) {
if (doc != null) {
console.log('YES');
callback(false, doc)
} else {
console.log('NO');
callback(false, null);
}
db.close();
});
});
};
var findUserByUUID = function(uuid, db, callback) {
var cursor = db.collection('players').find( { "uuid": uuid } );
cursor.each(function(err, doc) {
assert.equal(err, null);
if (doc != null) {
callback(false, doc)
} else {
callback(false, null);
}
});
};
exports.findUserByUUID = function (uuid, callback) {
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
findUserByUUID(uuid, db, function(err, data) {
callback(err, data);
db.close();
});
});
};
我知道我调用了 done() 两次,但是什么时候?我找不到它。 估计是路由的问题,不知道是哪里。
在您的 passport.use()
处理程序中,每次调用 done()
时,您都需要 return
以便它之后的代码不会也被执行。
现在您有一系列 if
语句,每个语句都可以调用 done()
,但它们不是 if/else
语句,因此您要测试的条件不止一个满足,因此 done()
可以被多次调用。
例如,更改为:
if (!user) { done(null, false, {message: 'Unknown user: ' + username})}
对此:
if (!user) {
done(null, false, {message: 'Unknown user: ' + username});
return;
}
并且,改变这个:
if (err) { done(err); }
对此:
if (err) {
done(err);
return;
}
或者,您可以将所有内容都变成 if/else if/else if/else
,这样只有一个分支可以执行。当您的多个 if
语句满足其条件然后被执行时,就会出现问题。
现在,您的 findUserByName()
在 cursor.each()
中调用其回调,因此它可以多次调用它,然后您会多次调用 done()
。