Using connect, express, and socket.io, I'm trying to allow my application to grab the session details when reconnecting. My sessions obviously work while the client is connected, but if I refresh the page on my browser, it forgets everything.
My session cookie is definitely the same, so it's not that.
My code's a big mish-mash of snippets I've taken from a number of different sources, since there doesn't seem to be one complete example application out there. :-/
What am I missing..?
var qs = require('querystring'),
express = require('express'),
app = express.createServer(),
io = require('socket.io').listen(app.listen(8000)),
routes = require('./routes'),
pCookie = require('connect').utils.parseCookie,
Session = require('connect').middleware.session.Session,
RedStore= require('connect-redis')(express),
sStore = new RedStore();
// Configuration
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser());
app.use(express.session({ store: sStore, secret: 'tehsecretz' }));
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(express.errorHandler());
});
// Routes
app.get('/', routes.index);
io.sockets.on('connection', function (client) {
var hs = client.handshake,
session = hs.session;
console.log('A socket connected called: ' + hs.sessionId);
var intervalId = setInterval(function() {
hs.session.reload(function() {
hs.session.touch().save();
});
}, 60 * 1000);
if (!session.userName) {
// Prompts the user for a name on the frontend
client.emit('need-to-register');
}
client.on('message', function(msg, c) {
console.log(session);
console.log(msg);
});
client.on('register-user', function(data, fn) {
// This retrieves the user's name
// and - hopefully - saves it to the session.
data = qs.parse(data);
session.userName = data.username;
hs.session.save();
console.log('Saving: ', session);
fn('ok');
});
client.on('disconnect', function() {
clearInterval(intervalId);
});
});
io.set('authorization', function (data, accept) {
if (data.headers.cookie) {
data.cookie = pCookie(data.headers.cookie);
data.sessionId = data.cookie['connect.sid'];
data.sessionStore = sStore;
sStore.get(data.sessionId, function (err, session) {
if (err || !session) {
accept('Error', false);
} else {
console.log(data.sessionId, session);
data.session = new Session(data, session);
accept(null, true);
}
});
} else {
return accept('No cookie transmitted', false);
}
});
Thanks for any help provided!
Ugh. So in Daniel Baulig's post on the subject, he referenced the identifier sessionID. I figured that was just poor convention (as I'm used to camelCase) and promptly changed it to sessionId in my code.
As I was debugging, I turned on MONITORing on my redis instance and noticed the session was being written to sess:undefined.
Turns out sessionID is special and is referenced internally as the actual identifier. Changing all instances of sessionId to sessionID allows me to have a better clue as to who is connecting!
Add 'cookie' in "express.session"
app.use(express.session({
secret: 'exampleSecretKey'
,store: exampleStore
,key: 'example'
cookie: {
path: '/'
,expires: false // Alive Until Browser Exits
,httpOnly: true
// ,domain:'.example.com'
}
});
Related
I am working on implementing social network application using node.js and the source that I use is Building Node Application with MongoDB and Backbone' by Mike Wilson.However, I cannot figure out the how to resolve the error of the MemoryStore --var MemoryStore = require('connect').session.MemoryStore;
Also, I tried to comment it but the error with middleware appear
var Session = require('connect').middleware.session.Session;
Can I get your help please ?
Thanks in advance
Here is the code of app.js
var express = require('express');
var http = require('http');
var app = express();
var nodemailer = require('nodemailer');
var MemoryStore = require('connect').session.MemoryStore;
var dbPath = 'mongodb://10.168.122.123:27017/socialnet';
var fs = require('fs');
var events = require('events');
// Create an http server
app.server = http.createServer(app);
// Create an event dispatcher
var eventDispatcher = new events.EventEmitter();
app.addEventListener = function (eventName, callback) {
eventDispatcher.on(eventName, callback);
};
app.removeEventListener = function (eventName, callback) {
eventDispatcher.removeListener(eventName, callback);
};
app.triggerEvent = function (eventName, eventOptions) {
eventDispatcher.emit(eventName, eventOptions);
};
// Create a session store
app.sessionStore = new MemoryStore();
// Import the data layer
var mongoose = require('mongoose');
var config = {
mail: require('./config/mail')
};
// Import the model
var models = {
Account: require('./models/Account')(app, config, mongoose, nodemailer)
}
// Configure the application
app.configure(function(){
app.sessionSecret = 'SocialNet secret key';
app.set('view engine', 'jade');
app.use(express.static(__dirname + '/public'));
app.use(express.limit('1mb'));
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({
secret: app.sessionSecret,
key: 'express.sid',
store: app.sessionStore
}));
mongoose.connect(dbPath, function onMongooseError(err) {
if (err) throw err;
});
});
// Import the routes located in ./routes
fs.readdirSync('routes').forEach(function(file) {
if (file[0] == '.') return;
var routeName = file.substr(0, file.indexOf('.'));
require('./routes/' + routeName)(app, models);
});
// -----
// GET /
// -----
app.get('/', function(req, res){
res.render("index.jade", {layout: false});
});
// -------------------
// POST /contacts/find
// -------------------
app.post('/contacts/find', function(req, res) {
var searchStr = req.param('searchStr', null);
if (null == searchStr) {
res.send(400);
return;
}
models.Account.findByString(searchStr, function onSearchDone(err, accounts) {
if (err || accounts.length == 0) {
res.send(404);
} else {
// TODO: Check if these accounts were already contacts
// if so, mark them as isContact so the views/Contact
// knows not to add a addButton
res.send(accounts);
}
});
});
// Let the server listen to 8000 (instead of the app)
app.server.listen(8000);
console.log('SocialNet listening to port 8000');
Your problem:
app.use(app.router)
, mounts your routes in that position in the call chain. You have it before your session middleware, so there is no req.session yet. When you leave it out, your routes will be positioned whenever you do your first app.get (or app.post and so on). If you still wish to control where your routes should be,
you can just:
move app.use(app.router) below the session middleware.
how to send file in nodejs, i am creating one page app, so i just want abcd.html page to be delivered on request for first time,
here is my code to that
app.js
var express = require('express'),
app = express(),
http = require('http'),
path = require('path'),
fs = require('fs'),
mysql = require('mysql'),
server = http.createServer(app),
passport = require('passport'),
flash = require('connect-flash'),
useragent = require('express-useragent'),
io = require('socket.io').listen(server);
// configuration ===============================================================
// connect to our database
require('./config/passport')(passport); // pass passport for configuration
app.use(express.static(path.join(__dirname, 'public')));
app.use(app.router);
app.configure(function() {
app.set('views', path.join(__dirname, 'app/views'));
app.set('view engine', 'ejs'); // set up ejs for templating
// required for passport
app.use(express.session({secret: 'vidyapathaisalwaysrunning',key: 'myuser.sid',cookie: { secure: false,maxAge:null}} )); // session secret1
//app.use(express.session({secret: 'vidyapathaisalwaysrunning', key: 'myownsid', cookie: { secure: false, maxAge: 3600000 }} )); // session with expitation
//app.use(express.session({ key: 'express.sid', secret: 'vidyapathaisalwaysrunning' } )); // 2 cookieId ie connect.sid & express.sid(user defined) session secret1
//app.use(express.session({ store: sessionStore, secret: 'vidyapathaisalwaysrunning',cookie: {httpOnly: false},key: 'cookie.sid' } )); // session secret
// set up our express application
app.use(express.logger('dev')); // log every request to the console
app.use(express.cookieParser()); // read cookies (needed for auth)
app.use(express.bodyParser()); // get information from html forms
app.use(useragent.express());
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash()); // use connect-flash for flash messages stored in session
app.use(express.static(path.join(__dirname, 'public')));
});
// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
//routes ======================================================================
require('./app/controller.js')(app, passport,io); // load our routes and pass in our app and fully configured passport
//require('./app/socket')(app,io);
// launch ======================================================================
server.listen(8080);
response to the page
case '/':
/*response.writeHead(200, {'Content-Type': 'text/html'});
response.write('hello world');*/
//response.json({ message: 'hello' });
response.sendfile("../public/abcd.html");
break;
it always gives Can't set headers after they are sent, here is the console output
Error: Forbidden
at SendStream.error (/home/pitu/CODING/NODE-PROJECTS/chichat/node_modules/express/node_modules/send/lib/send.js:145:16)
at SendStream.pipe (/home/pitu/CODING/NODE-PROJECTS/chichat/node_modules/express/node_modules/send/lib/send.js:307:39)
at ServerResponse.res.sendfile (/home/pitu/CODING/NODE-PROJECTS/chichat/node_modules/express/lib/response.js:339:8)
at /home/pitu/CODING/NODE-PROJECTS/chichat/app/controller.js:18:21
at callbacks (/home/pitu/CODING/NODE-PROJECTS/chichat/node_modules/express/lib/router/index.js:161:37)
at param (/home/pitu/CODING/NODE-PROJECTS/chichat/node_modules/express/lib/router/index.js:135:11)
at pass (/home/pitu/CODING/NODE-PROJECTS/chichat/node_modules/express/lib/router/index.js:142:5)
at Router._dispatch (/home/pitu/CODING/NODE-PROJECTS/chichat/node_modules/express/lib/router/index.js:170:5)
at Object.router (/home/pitu/CODING/NODE-PROJECTS/chichat/node_modules/express/lib/router/index.js:33:10)
at next (/home/pitu/CODING/NODE-PROJECTS/chichat/node_modules/express/node_modules/connect/lib/proto.js:190:15)
_http_outgoing.js:331
throw new Error('Can\'t set headers after they are sent.');
^ Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:331:11)
at ServerResponse.res.setHeader (/home/pitu/CODING/NODE-PROJECTS/chichat/node_modules/express/node_modules/connect/lib/patch.js:59:22)
at /home/pitu/CODING/NODE-PROJECTS/chichat/node_modules/express/node_modules/connect/lib/middleware/errorHandler.js:63:17
at fs.js:292:14
at Object.oncomplete (fs.js:93:15)
refrence screenshot
what to do
var event= require('./models/event');
var url = require('url');
var fs = require("fs");
//var app1 = require('../../app').app;
module.exports = function(app, passport,io)
{
//app.get('/createevent',event.createevent);
app.get('*', function(request, response)
{
var path = url.parse(request.url).pathname;
//use request object to get user data
//response.render('index');
switch(path){
case '/':
/*response.writeHead(200, {'Content-Type': 'text/html'});
response.write('hello world');*/
//response.json({ message: 'hello' });
//response.sendfile('../../public/abcd.htm', {root: __dirname })
response.sendfile('./public/abcd.htm');
break;
case '/creteevent':
console.log(" inside createevent ");
response.render('index123',{ title: 'The index page!' });
break;
case '/eventmember':
//response.render('index');
//this method is good becz below code , calling same as 4 both socket & http req
event.eventmember(function(err,returnedvalue)
{
if(returnedvalue){
console.log(" member result "+returnedvalue);
response.json(returnedvalue);
}else{
console.log(" member err "+ err);
}
});
break;
case '/eventtags':
var str = '{"eventid" :"2","associatedtags":["2","3"]}';
//response.render('index');
//this method is good becz below code , calling same as 4 both socket & http req
event.eventtags(str,function(err,returnedvalue)
{
if(returnedvalue){
console.log(" post result "+returnedvalue);
}else{
console.log(" posting err "+ err);
}
});
break;
case '/post':
var str = '{"eventid" :"2","selfid" :"2","title" :"feeedback to event","content" :"bla bla bla","lattitude" :"","longitude" :"","createddatetime" :"","posttype" :"idea","isapporved" :"no","isanonymous" :"no"}';
//response.render('index');
//this method is good becz below code , calling same as 4 both socket & http req
event.post(str,function(err,returnedvalue)
{
if(returnedvalue){
console.log(" post result "+returnedvalue);
}else{
console.log(" posting err "+ err);
}
});
break;
default:
response.writeHead(404);
response.write("opps this doesn't exist - 404");
break;
}
//just remove this line,& it worked, becz 2 response for a single request
***response.end();***
});
};
I'm use node.js + express + socket.io.
But when I'm tring to use cookies - I'm getting an error
no cookie transmitted
I have view all answers on this site. But don't find solution.
Here is my code of server:
// Require server config
var server_config = require('./config.json');
// Require express
var express = require("express");
var MemoryStore = express.session.MemoryStore;
var app = express();
var sessionStore = new MemoryStore();
// Configure app
app.configure(function () {
app.use(express.cookieParser());
app.use(express.session({secret: 'secret', key: 'express.sid'}));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname));
});
// Require socket IO and create server
var io = require('socket.io').listen(app.listen(server_config.port));
var history = {};
history.rooms = [];
var parseCookie = require('express/node_modules/cookie').parse;
io.set('authorization', function (data, accept) {
// check if there's a cookie header
if (data.headers.cookie) {
// if there is, parse the cookie
data.cookie = parseCookie(data.headers.cookie);
// note that you will need to use the same key to grad the
// session id, as you specified in the Express setup.
data.sessionID = data.cookie['express.sid'];
data.getSession = function (cb) {
sessionStore.get(data.sessionID, function (err, session) {
if (!err && !session) err = 'No session';
data.session = session;
cb(err, session);
});
}
} else {
// if there isn't, turn down the connection with a message
// and leave the function.
return accept('No cookie transmitted.', false);
}
// accept the incoming connection
accept(null, true);
});
// On connection actions
io.sockets.on('connection', function (socket) {
socket.handshake.getSession(function (error, session) {
console.log(error);
});
// Draw action
socket.on('drawClick', function (data) {
// Push element to the history
/*if (history.rooms[socket.room])
history.rooms[socket.room].push(data);*/
socket.broadcast.to(socket.room).emit('draw', {socket_id: socket.id, shape: data.shape, canvas_id: data.canvas_id, history: data.history});
});
// Subscribe to a room
socket.on('subscribe', function (data) {
socket.room = data.room;
socket.join(socket.room);
// If room history does not exists - create it
/*if (!history.rooms[socket.room])
history.rooms[socket.room] = [];
// If history exists - draw it
else
io.sockets.socket(socket.id).emit('history', {history: history.rooms[socket.room]});*/
});
// Note that it is not necessary to call socket.leave() during the disconnect event.
// This will happen automatically. Empty rooms will be automatically pruned so there is no need to manually remove them.
socket.on('unsubscribe', function (data) {
socket.leave(socket.room);
});
});
Here how I init on client:
io.connect(myprepa.config.site_url + ":" + myprepa.config.port);
Please help.
I am using express 3x, node.js and redis. when i as publishing message then 1 have receive this message 2-3 times in subscribe. (e.g. when i am refreshing my browser, message receive increase by 1 each time) .
below is my code.
server side :
~~~~~~~~~~
var express = require('express'),
http = require('http')
var redis = require('redis');
var redisCli = redis.createClient();
var redisPub = redis.createClient();
var redisSub = redis.createClient();
redisCli.on("error", function (err) {
console.error("\r\n Error generated from redis client ", err);
});
redisPub.on("error", function (err) {
console.error("\r\n Error generated from redisPub ", err);
});
redisSub.on("error", function (err) {
console.error("\r\n Error generated from redisSub ", err);
});
var server = http.createServer(app)
, io = require('socket.io').listen(server);
server.listen(process.env.PORT);
app.configure(function () {
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.set('view options', { layout: false });
app.use(express.favicon(__dirname + '/favicon.ico', { maxAge: 2592000000 }));
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({ secret: "myKey", store: new RedisStore({ maxAge: 86400000, client: redisCli }), cookie: { maxAge: 86400000} }));
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/static'));
});
io.configure(function () {
io.enable('browser client minification'); // send minified client
io.enable('browser client etag'); // apply etag caching logic based on version number
io.enable('browser client gzip'); // gzip the file
io.set('log level', 1);
io.set("flash policy server", false);
io.set("transports", ["jsonp-polling", "xhr-polling"]);
});
io.sockets.on('connection', function (client) {
console.log("server - redisSub.subscribe from io.on.connection");
redisSub.unsubscribe();
redisSub.subscribe("announcement");
redisSub.on("message", function (channel, message) {
io.sockets.emit('announcement', message);
});
client.on('disconnect', function () {
redisSub.unsubscribe("announcement");
redisSub.quit();
});
});
app.post('/PublishMessage', function (req, res) {
redisPub.publish("announcement", req.body.users);
res.setHeader('Cache-Control', 'max-age=0, must-revalidate, no-cache, no-store');
res.setHeader('Connection', 'keep-alive');
res.contentType('application/json');
res.setHeader('Expires', new Date().addYears(-10));
res.json({ result: 'ok' });
});
Client side
~~~~~~~~~
this.socket = io.connect('http://XXX.XXX.X.XXX/', { transports: ['jsonp-polling', 'xhr-polling'] });
this.socket.on('connect', function () {
alert("client - Socket client connect");
});
this.socket.on('announcement', function (msg) {
alert("clientside - announcement ");
var nUsers = parseInt($('#Summary>article>p:last').text(), 10) + parseInt(msg, 10);
$('#Summary>article>p:last').text(nUsers);
});
=================================================================
So, any one guide me for the same !!!
thank you very much.
I have never used socket.io, but it looks to me like you're over complicating things with your connection handler.
Inside the handler, it doesn't seem like you're reacting to the connection (like emitting a "user connected" event) or modifying the behavior of the individual socket connection in any way.
What you are doing, is repeatedly subscribing and unsubscribing the one redisSub client. I could be wrong here, but I don't think you need to or should be doing that.
Rather you should sub "announcement" once, outside of the connection handler, as you don't need to sub/unsub this global client on every connection. Like:
// Move this subscription outside of the connection handler, and you shouldn't
// have to continue to sub/unsub or otherwise manage it.
redisSub.on("message", function (channel, message) {
io.sockets.emit('announcement', message);
});
// Since you're not reacting to connections or doing anything with individual
// connection sockets, you don't really have anything to do in this handler.
io.sockets.on('connection', function (socket) {
// if you ONLY wanted to emit to this socket, you'd do it here
//socket.emit("announcement", "just for this connection")
});
Question:
Is it possible to store session data similar to $_SESSION['somedata'] = "Hello" in php?
Here is my code so far:
Creating the memory store
var MemoryStore = express.session.MemoryStore,
sessionStore = new MemoryStore();
Express Config
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser());
app.use(express.session({
store: sessionStore,
secret: 'secret',
key: 'express.sid'}));
app.use(require('stylus').middleware({src: __dirname + '/public'}));
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
Parsing the cookie to get the session id on handshake authorization
var parseCookie = require('connect').utils.parseCookie;
io.set('authorization', function (data, accept) {
if (data.headers.cookie) {
data.cookie = parseCookie(data.headers.cookie);
data.sessionID = data.cookie['express.sid'];
sessionStore.get(data.sessionID, function (err, session) {
if (err)
{
accept(err.message, false); //Turn down the connection
}
else
{
data.session = session; //Accept the session
accept(null, true);
}
});
} else {
return accept('No cookie transmitted.', false);
}
});
Storing 'loggedin' when the password and username are 'admin'
io.sockets.on('connection', function (socket) {
socket.on('details', function(data){
console.log("Details: " + data.u + data.p);
if(data.p == "admin" && data.u == "admin")
{
//Add the logged in field to the session
}
});
});
If the user is logged in redirect them to the home page
app.get(navigation.login.uri, function(req, res){
if(req.session.loggedin)
{
res.redirect('/home');
}
else
{
res.render('login', {
title: navigation.login.title,
navigation: navigation
});
}
});
When I try to use:
req.session.loggedIn
The value is undefined. Could this be a storage problem, or am I accessing it incorrectly?
You're close - just missing a couple of things.
The information that you are gathering in the socket authorization function is accessible via socket.handshake in your connection handler.
So, what I think you want is:
io.sockets.on('connection', function (socket) {
socket.on('details', function(data){
console.log("Details: " + data.u + data.p);
if(data.p == "admin" && data.u == "admin")
{
//Add the logged in field to the session
socket.handshake.session.loggedIn = true; // Set the new session var
socket.handshake.session.save(); // Save the modified session
}
});
});
Don't forget to save the session after modifying it otherwise it never gets back into the store.
This worked for me - you basically just have to set a key in the sessionStore:
io.sockets.on('connection', function (socket) {
socket.on('details', function(data){
console.log("Details: " + data.u + data.p);
if(data.p == "admin" && data.u == "admin")
{
// set the value
sessionStore.loggedIn = true;
// get the value
console.log(sessionStore.loggedIn);
}
});
});
I tried it on a website with some subpages, the value was consistent. A forced reload or closing the browser resets it.