Nodejs/Express Session - Error: Can't set headers after they are sent - express-session

I am getting the below error while trying to use express session with a simple nodejs sample app.
When "resave" is set to true the below error appears, however when the same is set to false, there is no error.
GET / 304 13.380 ms - - Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)
at ServerResponse.header
(/Volumes/SURESH/GSKLabs/NodeApp/node_modules/express/lib/response.js:718:10)
at ServerResponse.contentType
(/Volumes/SURESH/GSKLabs/NodeApp/node_modules/express/lib/response.js:551:15)
at ServerResponse.send
(/Volumes/SURESH/GSKLabs/NodeApp/node_modules/express/lib/response.js:138:14)
at done
(/Volumes/SURESH/GSKLabs/NodeApp/node_modules/express/lib/response.js:957:10)
Below is the code app.js
var express = require('express');
var session = require('express-session');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var mongojs = require('mongojs');
var mongoStore = require('connect-mongo')(session);
var db = mongojs('mongodb://localhost:27017/checker', ['sessions']);
var routes = require('./routes/index');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
var sessionStore = new mongoStore({
db: db,
})
// Session details
app.use(session({
secret: 'check first',
name: {secure: true, maxAge: 60000},
store: sessionStore, // connect-mongo session store
proxy: true,
resave: true,
saveUninitialized: true
}));
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace/Volumes/SURESH/GSKLabs/NodeApp/node_modules/express/lib/router/index.js:310:13
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
routes/index.js
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
package.json
{
"name": "NodeApp",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www"
},
"dependencies": {
"body-parser": "~1.15.1",
"connect-mongo": "^1.3.2",
"cookie-parser": "~1.4.3",
"debug": "~2.2.0",
"ejs": "~2.4.1",
"express": "~4.13.4",
"express-session": "^1.14.1",
"mongojs": "^2.4.0",
"morgan": "~1.7.0",
"serve-favicon": "~2.3.0"
}
}
As per my understanding, since the resave:true, express session trying to set the cookie after the response is already sent. Cannot change to resave:false, as it needs to be "true" for using rolling option in express session.
Any help how to solve this error in the above sample code. Thanks.

Related

Express-session does not create any session

Im trying to implement some basic sessions functionality in my toy project with express-session and connect-mongo for session storage.
What i expect:
Browser gets cookie after recieving response from server
Session data is written to collection "sessions"
I get debug messages from express-session in console, because i start the app with DEBUG=express-session:* nodemon ./bin/www
What i get instead:
Browser never gets cookie
No documents are being created in the collection (the collection itself is being created every time i launch the app though)
There are no debug messages from express-session in the console
Everything related to DB and session setups in the app.js file:
// DB setup
var mongoDB = require('./k'); // K is a file containing connection string
mongoose.connect(mongoDB, {
useNewUrlParser: true,
useUnifiedTopology: true
})
var db = mongoose.connection
db.on('error', console.error.bind(console, 'MongoDB connection Error: '))
// Session setup
const connection = mongoose.createConnection(mongoDB, {
useNewUrlParser: true,
useUnifiedTopology: true
})
const sessionStore = new MongoStore({
mongooseConnection: connection,
collection: 'sessions'
})
app.use(session({
secret: 'some secret',
resave: false,
saveUninitialized: true,
store: sessionStore,
cookie: {
maxAge: 1000 * 60 * 60 * 24
}
}));
Is there anything i clould be missing? What could be causing this issue for me?
Try:
var MongoStore = require('connect-mongostore')(session);
app.use(session({
secret: 'my secret',
store: new MongoStore({'db': 'sessions'})
}));
Looks like the problem was being caused by the order of middleware in my app.js file. I moved the code with DB setup and session setup right above routers and it worked. app.js before:
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var entriesRouter = require('./routes/entries')
const categoriesRouter = require('./routes/categories')
const session = require('express-session');
const MongoStore = require('connect-mongo')(session)
const mongoose = require('mongoose')
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({
extended: false
}));
// app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/entries', entriesRouter)
app.use('/categories', categoriesRouter)
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
// DB setup
var mongoDB = require('./k'); // K is a file containing connection string
mongoose.connect(mongoDB, {
useNewUrlParser: true,
useUnifiedTopology: true
})
var db = mongoose.connection
db.on('error', console.error.bind(console, 'MongoDB connection Error: '))
// Session setup
const connection = mongoose.createConnection(mongoDB, {
useNewUrlParser: true,
useUnifiedTopology: true
})
const sessionStore = new MongoStore({
mongooseConnection: connection,
collection: 'sessions'
})
app.use(session({
secret: 'some secret',
resave: false,
saveUninitialized: true,
store: sessionStore,
cookie: {
maxAge: 1000 * 60 * 60 * 24,
secure: false
}
}));
module.exports = app;
app.js after:
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var entriesRouter = require('./routes/entries')
const categoriesRouter = require('./routes/categories')
const session = require('express-session');
const MongoStore = require('connect-mongo')(session)
const mongoose = require('mongoose')
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({
extended: false
}));
// app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// DB setup
var mongoDB = require('./k'); // K is a file containing connection string
mongoose.connect(mongoDB, {
useNewUrlParser: true,
useUnifiedTopology: true
})
var db = mongoose.connection
db.on('error', console.error.bind(console, 'MongoDB connection Error: '))
// Session setup
const connection = mongoose.createConnection(mongoDB, {
useNewUrlParser: true,
useUnifiedTopology: true
})
const sessionStore = new MongoStore({
mongooseConnection: connection,
collection: 'sessions'
})
app.use(session({
secret: 'some secret',
resave: false,
saveUninitialized: true,
store: sessionStore,
cookie: {
maxAge: 1000 * 60 * 60 * 24,
secure: false
}
}));
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/entries', entriesRouter)
app.use('/categories', categoriesRouter)
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;

Error 404 Not Found Using Pug & Express and MongoDB

I am getting at 404 not found error using Express & MongoDB for a POST request. I tried to redo my routes numerous times, but am having trouble with the login page. I want to POST the information to my server and render a simple "Welcome Message."
Please advise.
Routes Folder:
var express = require('express');
var router = express.Router();
let mongoose = require('mongoose');
var User = require('../models/users')
//Get registration page from index button//
router.get('/register', function(req, res, next) {
res.render('register');
if (err) return console.error(err);
res.json(user);
});
//Post user data to database POST /register //
router.post('/register', function(req, res, next) {
res.render('Welcome to Fit 7');
})
var username = req.body.username;
var email = req.body.email;
var password = req.body.password;
var newuser = new User();
newuser.username = username;
newuser.email = email;
newuser.password = password;
newuser.save(function(err, savedUser) {
if(err) {
console.log(err);
return res.status(500).send();
}
return res.status(200).send();
})
module.exports = router;
App JS Code:
// var createError = require('http-errors');
var express = require('express');
var app = express();
var path = require('path');
// var cookieParser = require('cookie-parser');
var logger = require('morgan');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var pug = require('pug');
// var indexRouter = require('./routes/index');
var workouts = require('./routes/workouts');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
// view engine setup
app.set('view engine', 'pug');
app.set('views', path.join(__dirname, 'views'));
// app.use(cookieParser());
// app.use(express.static(path.join(__dirname, 'public')));
// app.use('/', indexRouter);
// app.use('/api/workouts', workouts);
app.get('/', function (req, res) {
res.render('index')
})
//Registration Route for New Users
app.get('/register', function (req, res) {
res.render('register')
});
app.get('/home', function (req, res) {
res.render('home');
});
app.get('/workout/new', function (req, res) {
res.render('workoutform');
});
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
Pug Template Code:
body(data-gr-c-s-loaded='true', style='')
.container
form(action='/register', method='post').form-signin
h1.form-signin-heading Login to Fit-7
label.sr-only(for='username') Name
input#name.form-control(type='username', placeholder='username',
required='', autofocus='')
label.sr-only(for='email') Email address
input#inputEmail.form-control(type='email', placeholder='email address',
required='', autofocus='')
label.sr-only(for='password') Password
input#password.form-control(type='password', placeholder='password',
required='')
button.btn.btn-lg.btn-primary.btn-block(type='submit') Sign in
span._hsShareImage.hsShareImage  
loom-container#lo-engage-ext-container
loom-shadow(data-reactroot='', classname='resolved')
You dont seem to import the router anywhere in your app.js. First add
var registerRoute = require("./path/to/route.js");
after your other requires. Then add
app.use(registerRoute)
in place of this line:
app.get('/register', function (req, res) {
res.render('register')
});
I still dont have a reputation to like the comment above or comment, but the answer was very helpful.
But my problem was that I had the bellow line:
app.use('/', routes);
So I changed to where my application was
app.use('/Live/api', routes);
I'm using express with pug

node js and passport validation miss passport session

I have app.js as below
var express = require('express'),
path = require('path'),
favicon = require('serve-favicon'),
logger = require('morgan'),
cookieParser = require('cookie-parser'),
bodyparser = require('body-parser'),
db = require('./model/db');
var app=express();
var dbConfig = require('./db.js');
var mongoose = require('mongoose');
mongoose.Promise = global.Promise;
mongoose.createConnection(dbConfig.url);
var passport = require('passport');
app.use(bodyparser.urlencoded({
extended:true
}));
var expressSession = require('express-session');
var flash = require('connect-flash');
app.use(expressSession({
secret: 'crackalackin',
resave: true,
saveUninitialized: true,
cookie : { secure : false, maxAge : (4 * 60 * 60 * 1000) }, // 4 hours
}));
app.use(passport.initialize());
app.use(passport.session());
// Using the flash middleware provided by connect-flash to store messages in session
// and displaying in templates
var flash = require('connect-flash');
app.use(flash());
// Initialize Passport
var initPassport = require('./passport/init');
initPassport(passport);
var routes = require('./routes/index')(passport);
app.use('/', routes);
/// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
app.listen(6061,function(){
console.log("started on port 6061");
});
/passport/init.js
var login = require('./login');
var signup = require('./signup');
var User = require('../models/user');
module.exports = function (passport) {
// Passport needs to be able to serialize and deserialize users to support persistent login sessions
passport.serializeUser(function (user, done) {
done(null, user._id);
});
passport.deserializeUser(function (id, done) {
try {
User.getById(id, function (err, user) {
done(err, user);
});
} catch (ex) {
}
});
// Setting up Passport Strategies for Login and SignUp/Registration
login(passport);
signup(passport);
}
when I write console.log(req.session) in /passport/login.js at validation function.
I get output like
Session {
cookie:
{ path: '/',
_expires: 2017-02-01T14:10:38.523Z,
originalMaxAge: 14400000,
httpOnly: true,
secure: false } }
I miss the
passport: {}
so I can login but can not generate passport session.
So isAuthenticated function say "login plase".
how can I manage session here.

Switching from Localhost MongoDB, to deploying on Heroku with MongoLab

I'v build an app on my local machine using MongoDB, and this is fully working locally. But once I deploy it to Heroku I cannot connect to the DB or retrieve anything from the REST service. I'v read the docs many time and noticed they need to be updated in many places which is throwing me off. Here is my initialize code:
Any help or suggestions much appreciated.
"use strict";
var express = require("express");
var path = require("path");
var favicon = require("serve-favicon");
var logger = require("morgan");
var cookieParser = require("cookie-parser");
var bodyParser = require("body-parser");
var server = express();
server.set("port", (process.env.PORT || 5000));
server.use(express.static(__dirname + "/public"));
server.listen(server.get("port"), function() {
console.log("Node server is running at localhost:" + server.get("port"));
});
var router = express.Router();
/* GET home page. */
router.get("public", function(req, res) {
res.render("index", { title: "MyApp" });
});
module.exports = router;
// **** LocalDB: "mongodb://localhost:27017/myapp" ****
var mongo = require("mongoskin");
var db = mongo.db("mongodb://xxxxxx:xxxxxx#ds045511.mongolab.com:45511/xxxxxx", {native_parser:true});
var routes = require("./routes/index");
var users = require("./routes/users");
var divesites = require("./routes/myCollection");
var app = express();
// view engine setup
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "jade");
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + "/public/favicon.ico"));
app.use(logger("dev"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, "public")));
// Make our db accessible to our router
app.use(function(req,res,next){
req.db = db;
next();
});
app.use("/", routes);
app.use("/users", users);
app.use("/myCollection", myCollection);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error("Not Found");
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get("env") === "development") {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render("error", {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render("error", {
message: err.message,
error: {}
});
});
module.exports = app;
You could use the environment variable process.env.MONGOLAB_URI instead and see how that goes:
var mongo = require("mongoskin");
var db = mongo.db(process.env.MONGOLAB_URI, {native_parser:true});

Why wont this post?

I'm playing around with mongodb + Express and rewriting an old comments app in the latest version of Express.
I've had to change a few things because of the changes in the latest Express. But I'm having some issues.
Basically, it won't post to /create when I submit my form. This is probably a simple fix but any help would be appreciated :)
app.js
require('./models/comments'); // require the model before the 'index.js' file is called
var express = require('express'); var path = require('path'); var favicon = require('static-favicon'); var logger = require('morgan'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser');
var routes = require('./routes/index'); var create = require('./routes/create');
var app = express();
// Database stuff var mongoose = require('mongoose'); mongoose.connect('mongodb://localhost/comments-app');
// view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade');
app.use(favicon()); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded()); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes); app.use('/create', create);
/// catch 404 and forward to error handler app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err); });
/// error handlers
// development error handler // will print stacktrace if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
}); }
// production error handler // no stacktraces leaked to user app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
}); });
module.exports = app;
Comments.js (model)
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var CommentSchema = new Schema({
username: String,
content: String,
created: Date
});
module.exports = mongoose.model('Comment', CommentSchema);
index.jade
extends layout
block content
h1= title
div.addCommentForm
form( method="post", action="/create")
input(type='text', class='nameTxt', name='username')
div
span.label Comment :
textarea(name='comment')
div#addCommentSubmit
input(type='submit', value='Save')
br
br
#comments
- each comment in comments
div.comment
div.name comment.username
div.created_at= comment.created
br
div.content= comment.content
hr
create.js (route)
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var Comment = mongoose.model('Comment', Comment);
router.route('/create')
.post(function(req, res) {
var Comment = new Comment()
username : req.body.username;
content : req.body.comment;
created : Date.now();
Comment.save(function(err) {
if (err)
res.send(err);
res.send('Comment added');
});
});
module.exports = router;
Your jade indenting for the form tag is off. Make sure the input tags you want inside the form tag in the HTML are indented further than the form tag in your jade so they end up as children of the form tag in the HTML.
Oops:
this jade
form
input
yields this HTML
<form></form><input>
Fixed
form
input
yields
<form><input></form>