const express = require("express");
const app = express();
var i = new Number;
i=0;
app.get("/", function(req, res){
i++
console.log(i);
});
app.listen(8080);
I created a very small node js project. I have a problem. when I create a variable like above, it doesn't evaluate for each user separately. that is, when a user requests a get, I want it to be 1 each time.
Sample
my problem is that when a jack user enters a site, if he doesn't log out, someone who enters the site's home page from another device enters his account with jack.
how can I do that?
The simplest answer for your question is to simply declare and increment the variable inside the function passed to app.get, but I'm going to assume that you would like a situation where, for a given user's series of requests, the number will increment.
The simplest way to do this is using a server side session, which is provided by the express-session library. Additionally, in order for this to work, you need to call res.end() in order to send the cookie associated with the server session back to the user's browser. More information on sessions generally can be found here.
Below is code to replicate the intent of what you have there, but incrementing for each request from a unique browser instance (identified by the same cookie value associated with the server session):
const express = require('express');
const session = require('express-session');
const app = express();
app.use(session({
resave: false,
saveUninitialized: true,
secret: 'secret',
cookie: {
maxAge: 60000
}
}));
app.get('/', function(req, res){
if (!req.session.value) {
req.session.value = 0;
}
req.session.value++;
console.log(req.session.value);
res.end();
});
app.listen(8080);
Related
Im trying to think of a solution to the following issue:
I have a variable that needs to be separate for every unique visitor on the page. Its just simple list that is filled when a visitor clicks on some items on the page. It would be empty for each unique visit.
Currently Im keeping that in the backend, it is pretty bad solution as everyone currently using the app is adding to the same list
The backend code:
thelist=[]
app.get("/show/:id", function (req, res) {
var id = req.params.id;
thelist.push(id)
console.log(thelist);
res.redirect('/')
});
app.get("/run", function(req, res) {
res.render("data", {data: thelist})
thelist = []
});
The main point is that list thelist is then passed to a python script which is also connected via node.js into the app. Therefore i need that variable to stay in the backend.
Also I was thinking of keeping it simple, so I don't want to force users to create account to use the app, so some sort of cookies/cache/any other form of session storage is what im looking for.
You can create a session map(like hashmaps). I have integrated the same in one of my projects and it is working flawlessly. Below is the code for it and how you can access it:
hashmap.js
var hashmapSession = {};
exports.auth = auth = {
set : function(key, value){
hashmapSession[key] = value;
},
get : function(key){
return hashmapSession[key];
},
delete : function(key){
delete hashmapSession[key];
},
all : function(){
return hashmapSession;
}
};
app.js
var hashmap = require('./hashmap');
var testObj = { id : 1, name : "john doe" };
hashmap.auth.set('test', testObj);
hashmap.auth.get('test');
hashmap.auth.all();
hashmap.auth.delete('test');
You can use this approach as a session storage for your node application. Keep in mind that this storage will only be persistent for the current session only.
The best solution here would be express session (https://github.com/expressjs/session)
As I see your code I can figure out you are using express. And if you are using express that is enough for below code.
Here is the easiest way with minimal code to achieve what you are looking for:
Example:
app.set('oneSetting', 'one');
console.log(app.settings.oneSetting);
OR
app.set('port', 3000);
app.get('port'); //3000
You can access the same variables in the req object too, example:
req.app.get('port')
Why don't you use express-session.
You can use it like the following :
App.js
var app = express();
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}))
Controller.js
//Sets the id in the session object.
app.get('/show/:id', function (request, response, next) {
request.session.id = id;
})
//Retrieve the id from the session object.
app.get('/showMyId',function(request,response,next)){
response.send(request.session.id;);
})
This way you do not have to manage the global list and all your ids would be present inside their respective session object.
This approach uses a cookie session , there are also alternative strategies available for storing your session object like a proper storage server.
From my understanding you are trying to count no.of unique visitors for your application.
You can use simple cookie to track use and set expiry long time so cookie is not erased.
Express had cookie parser module which will automatically parse cookie.
thelist={}
var express = require('express')
var cookieParser = require('cookie-parser')
var app = express()
app.use(cookieParser())
app.get("/show/:id", function (req, res) {
var visitorId = req.cookies.visitorid;
var id = req. params.id
if(!req.cookies[id]){
///create unique id like GUID or something which allows you to uniquely identify user
if(!visitorId){
visitorId = '<GUID>';
}
if(!thelist[visitorId]){
thelist[visitorId] = [];
}
thelist[visitorId].push(id);
console.log(thelist);
}
res.cookie('visitorid',visitorId, { maxAge: 900000, httpOnly: true }); //You can extend max age as required. Setting up every time will also extend expiry.
res.cookie(id,'visited', { maxAge: 900000, httpOnly: true }); //set cookie with id saying this is allready visited
res.redirect('/')
});
app.get("/run", function(req, res) {
res.render("data", {data: thelist})
thelist = []
});
you can use sessionstorage on your window session
sessionStorage.setItem(KEY,VALUE);
I am trying to access my session token from other routes after setting it in a route. I am currently unsuccessful. Following the relevant code of the three files.
server.js: It calls the routes thermostats, login and also sets session token.
var session = require('express-session');
var app = express();
app.use(session({secret: 'keyboard cat',cookie: { secure: true }}))
var router = express.Router();
var thermostats = require('./api/routes/thermostats')(router, app, session);
require('./api/routes/login')(router, app, session, thermostats);
login.js: When the user goes to localhost:3000/login/, the login token needs to be saved in the session
module.exports = function(router,app, session, thermostats){
router.get('/login/', function(req, res) {
list(req, res) //response of this function has session which needs to be saved.
console.log(res.session)
app.use(session(res.session)) //trying to save the res.session as session token
});
}
thermostat.js: Needs to access the session token before can display any information.
module.exports = function(router,app){
router.get('/thermostats/', function(req, res) {
console.log(req.session) //Set to default/null values and not the updated session values
});
}
It might be something small but I cannot figure out the issue. I would appreciate any help.
Thank you
Express-session should automatically save the session, based on the configuration.
Looking at the 'resave' config option in the express-session docs:
resave
Forces the session to be saved back to the session store, even if the session was never modified during the request. Depending
on your store this may be necessary, but it can also create race
conditions where a client makes two parallel requests to your server
and changes made to the session in one request may get overwritten
when the other request ends, even if it made no changes (this behavior
also depends on what store you're using).
This is by default, true, so it should already start working without you needing to add app.use(session(res.session).
Edit: You will be able to save to the session by adding fields to the req.session object:
router.get('/login/', function(req, res) {
getDataFromExternalApi(req, function(err, apiResponse) {
var data = apiResponse.data;
req.session.data = data;
// if resave option is true, this should automatically save to the session store after this request is done.
});
});
Generally, you shouldn't be using app.use in your request handlers. Those are generally reserved for setting up the server, as it defines what middleware express uses.
I'm using cookie-parser, all the tutorial talk about how to set cookie and the time it expiries but no where teach us how to get the value of these cookie
For people that stumble across this question, this is how I did it:
You need to install the express cookie-parser middleware as it's no longer packaged with express.
npm install --save cookie-parser
Then set it up as such:
const cookieParser = require("cookie-parser");
const app = express();
app.use(cookieParser());
Then you can access the cookies from
req.cookies
Hope that help.
First note that Cookies are sent to client with a server request and STORED ON THE CLIENT SIDE. Every time the user loads the website back, this cookie is sent with the request.
So you can access the cookie in client side (Eg. in your client side Java script) by using
document.cookie
you can test this in the client side by opening the console of the browser (F12) and type
console.log(document.cookie);
you can access the cookie from the server (in your case, expressjs) side by using
req.cookies
Best practice is to check in the client side whether it stored correctly. Keep in mind that not all the browsers are allowing to store cookies without user permission.
As per your comment, your code should be something like
var express = require('express');
var app = express();
var username ='username';
app.get('/', function(req, res){
res.cookie('user', username, {maxAge: 10800}).send('cookie set');
});
app.listen(3000);
hope this will help you
const app = require('express')();
app.use('/', (req, res) => {
var cookie = getcookie(req);
console.log(cookie);
});
function getcookie(req) {
var cookie = req.headers.cookie;
// user=someone; session=QyhYzXhkTZawIb5qSl3KKyPVN (this is my cookie i get)
return cookie.split('; ');
}
output
['user=someone', 'session=QyhYzXhkTZawIb5qSl3KKyPVN']
Just want to add that we shouldn't be using modules to do trivial stuff. Modules are very convenient and fast forward development, but keep us from learning by creating infrastructural code.
I'm a professor not a boss so I value more programmers knowledge/skill development than to write code in lesser time without learning anything...
Back to business...
Unless you need signed cookies, or anything more complex, it's perfectly possible to write your own middleware to parse cookies and add the values to the rest of the pipeline as the module does.
app.use((req, res, next) => {
const { headers: { cookie } } = req;
if (cookie) {
const values = cookie.split(';').reduce((res, item) => {
const data = item.trim().split('=');
return { ...res, [data[0]]: data[1] };
}, {});
res.locals.cookie = values;
}
else res.locals.cookie = {};
next();
});
Anywhere you need to read the cookie it's available via res.locals.cookie, conveniently formatted as an object.
You could even add a custom cryptography strategy here to make sure no one is reading your cookie.
Just remember middlewares are ordered, so this one has to be added before any other middleware or route that uses the cookie.
My code is listed below but I wanted to explain my thought process and have someone correct me at every point because I have been struggling to try and get this done the RIGHT way.
I've been struggling with this for some time(5days+) and I have not found a straight forward way to do this across the web.
So I have 2 separate node apps running. One running just express-js and another running a websocket server. I'm probably just a complete knucklehead with this, but here goes.
I setup a mongo session store. When a user successfully authenticates, the session gets created and I can re-direct the user to the logged in page. While the session lives, when the user hits the 'auth-page' I can just auto redirect the user to the 'logged in page'.
Now my understanding is, when the session gets created in the mongo-store, a cookie gets created on the web browser and it is this cookie that gets to the server for each request the page makes and express-js will nicely handle the magic internally for me and I can use something like
app.post('/', function (req, res) {
}
Where the req variable gets populated with the session id by express, because express got the cookie and decoded it.
This next part is where things are dicey and any suggestions in anyway will be a huge help.
What i'm wanting to do is, inside my app.post('/'...etc) is redirect to another page. This page loads a client which initiates a websocket connection to my websocket server and my websocket server is able to use this same session-id.
So here's the thing. My express-js http server runs as a separate process with its own port and my websocket server runs as a separate process with its own port as well. After doing enough research online, I found out many sources which indicated that, when my browser makes the connection to my websocket server it will send the cookie in the header somewhere to my websocket server. So in the browser, I have some javascript code that runs:
let clientSocket = new WebSocket("ws://socket.server.address:5005");
So then from my node websocket server, I can parse out the socket.upgradeReq.headers , get the cookie, and use that to get the session id and i'm in business. That describes what I've attempted to achieve below in my code. I have been successful doing this, however I've hit different issues when trying to parse the cookie.
Sometimes I get a single cookie & sometimes, I get multiple cookies taking the form
cookie_name1=cookie_value1;cookie_name2=cookie_value2;
cookie_name3=cookie_value3;cookie_name4=cookie_value4;
cookie_name5=cookie_value5;
Sometimes I get a single cookie & sometimes, I get multiple cookies taking the form
question 1 - why do I get multiple cookies being sent to my websocket server? Is that dictated strictly by the browser? What can I do about that if anything?
question 2 - Will the cookies ALWAYs come in that format? I would hate for the semicolon delimiter style to change and that break my code
question 3 - upon reviewing my code, my thought process can you suggest and guide me with a complete different/better implementation to achieve this? Can you suggest I change parts? My goal is to be able to spin up multiple different websocket servers & webservers and load-balance between them. I'm trying to find a reliable way to do this so that my code doesn't break... my node apps are just very frail, some direction would help. It seems like for nodejs, despite its maturity in 2017, good information lives only on stackoverflow,github issue threads and irc.freenode and I classify some of these things as basic...
packages and versions used
web-server package versions
---------------
express#4.15.2
express-session#1.15.2
mongodb#2.2.26
cookie-parser#1.4.3
body-parser#1.17.1
connect-mongodb-session#1.3.0
socket-server package versions
---------------
uws#0.14.1
below is my code
webserver.js
'use strict';
const bodyparser = require('body-parser');
const cookieparser = require('cookie-parser');
const express = require('express');
const app = express();
const express_session = require('express-session');
const connect_mongo = require('connect-mongodb-session')(express_session);
const port = process.env.NODE_WEBSERVER_PORT;
const _ = require('underscore');
const mongo_store = new connect_mongo({
uri: 'mongodb://mongo1.weave.local:27017/sessiondb',
collection: 'sess'
});
const session_time = 1000 * 60 * 5 ; // 5 minute(s)
app.use(express_session({
secret: 'superman',
cookie: {
maxAge: session_time,
httpOnly: false
},
store: mongo_store,
resave: false,
saveUninitialized: false,
name: 'inspect_the_deq',
httpOnly: false
}));
app.use(bodyparser.urlencoded({ extended: false }))
app.use(bodyparser.json());
app.set('view engine', 'pug');
app.set('views', __dirname+'/pugs')
app.use(express.static(__dirname + '/com/js'));
app.use(express.static(__dirname + '/com/asset'));
const mongo = require('mongodb').MongoClient;
const mongo_url = 'mongodb://mongo1.weave.local:27017/main';
let account = null;
let database = null;
mongo.connect(mongo_url, function(err, db) {
let collection = db.collection('account');
account = collection;
database = db;
});
app.get('/', function (req, res) {
if(req.session.user){
const user = req.session.user;
res.render('main', {message: 'user '+user+' logged in' });
console.log('session found logging you on');
}else{
res.render('login', {message: 'Login'});
console.log('no session exists');
}
});
app.post('/', function (req, res) {
const user = req.body.username, pass = req.body.password;
const seconds = session_time;
account.findOne({username: user, password: pass }, function(err, document) {
if( document !== null ){
req.session.user = user;
req.session.cookie.expires = new Date(Date.now() + seconds);
req.session.cookie.signed = true;
res.render('main', {message: 'user '+user+' logged in'});
console.log('some id is '+req.session.id);
console.log('cookie id is '+req.session.cookie);
console.log('sess id is '+req.sessionID);
}else
res.render('login', {message: 'Login', login_error: 'invalid username or password'});
});
});
app.listen(port, function () {
console.log('http server '+port);
});
Socket Server code here
'use strict';
const _ = require('underscore');
const uwsPlugin = require('uws').Server;
const socket_port = process.env.NODE_SOCKET_PORT;
const ws = new uwsPlugin({ port: socket_port, maxPayload: 0 });
//const Meepack = require('./core/meepack');
const cookieparser = require('cookie-parser');
const express_session = require('express-session');
const connect_mongo = require('connect-mongodb-session')(express_session);
const mongo_store = new connect_mongo({
uri: 'mongodb://mongo1.weave.local:27017/sessiondb',
collection: 'sess'
});
ws.on('connection', function connection(socket) {
'use strict';
console.log('client verification process ');
let headers = Object.keys(socket.upgradeReq.headers);
let upgradeReq = Object.keys(socket.upgradeReq.headers.cookie);
let cookie = socket.upgradeReq.headers.cookie;
//use the cookie here to get the session_id and do whatever you want
socket.on('close', function close(e) {
console.log('connection closed');
});
socket.on('message', function close(data) {
'use strict';
});
});
I set up session management in my node js/ express js website successfully. I stores session data in mongo db. I want the session to be valid for the users who log in for a couple of weeks. The code is as follows:
var cookieParser = require('cookie-parser');
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);
app.use(cookieParser());
app.use(session({
store: new MongoStore({ mongoose_connection: db }),
secret: 'cookie_secret',
cookie: { maxAge: null }
}));
It works fine for normal users, but my problem is with web crawlers such as google bots and facebook bots. I still want them to crawl my website but I don't want their sessions to be stored in my mongo db. It's taking up lots of space and storage is increasing daily which costs me money.
How to selectively choose which sessions to be stored in the db. I can check for req.headers['user-agent'], but where to use it in my code? How to tell express-session not to store session sometimes?
You can use the session middleware conditionally, based on the User-Agent header. A simple example:
var sessionMiddleware = require('express-session')({
...configuration here...
});
app.use(function(req, res, next) {
var ua = req.get('user-agent');
// If the User-Agent header contains the string "Googlebot",
// skip the session middleware.
if (/Googlebot/.test(ua)) {
req.session = {}; // perhaps a bit too simple?
return next();
}
return sessionMiddleware(req, res, next);
});
It would depend on your actual use of req.session if the code above works, or if you need to mock req.session a bit better (for instance, if you use any of the req.session methods in your code,
you may need to mock those too).