I have a problem in my bluemix application when the project has two or more instances.
If I keep the project with only one instance, this code works as expected and when the url '/load' is called, I receive the data saved in the '/save'. But, when I put more instances in the application, the '/load' sends nothing is most times.
Its like the session is saved in one instance of the project and when the user hits another url, the '/load' is being executed in another instance.
So, does anyone knows how to make sure that the user only use one instance or share the session value between the instances?
var express = require('express');
var session = require('express-session');
var cfenv = require('cfenv');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var app = express();
app.use(express.static(__dirname + '/public'));
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(session({
resave: 'false',
saveUninitialized: 'true',
secret: 'cub1ksqu4d_mysp0t'
}));
var appEnv = cfenv.getAppEnv();
app.get("/save", function (req, res) {
req.session.fullname = "John Galt";
res.send("Saved session");
});
app.get("/load", function (req, res) {
res.send(req.session.fullname);
});
app.listen(appEnv.port, '0.0.0.0', function () {
console.log("server starting on " + appEnv.url);
});
You should design your app as stateless process. This is actually one of the 12 factors (see 12 factor app).
If you want to share a state between invocations and between instances of your app, a common practice is to use a database to store that data. There are frameworks to allow caching of data/states across the instances.
Seems that each instance it have their own request manager and it's not shared and each request is balanced through all instances.
You can make the /save to take a name parameter and test to execute /save a few times with different names and then the /load to see if it returns "randomly" the different names given.
If you want to share information through multiple instances I would recommend the use of a db service on your app.
Related
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);
I have an application running on Oracle Linux 7 with Node.js v4.4.3. Our server has two DNS servers defined in resolv.conf. We Recently had the primary DNS server fail, so the secondary DNS server defined in resolv.conf should have worked. But Node.js failed to use the secondary server. It was almost as if it ignored the secondary and only tried to use the primary.
I thought it might have been an OS issue, so I manually modified the resolv.conf file and tested with DIG and it correctly used the secondary server, but when I tried with Node, it just wouldn't work. I wrote the program below to do some testing, basically modifying the resolv.conf while the program ran and nothing.
"use strict";
var dns = require('dns');
var express = require('express');
var bodyParser = require('body-parser');
var expressHandlebars = require('express-handlebars');
var cookieParser = require('cookie-parser');
var httpClient = require('request-promise');
//Initialize Express and Handlebars
var app = express();
app.enable('trust proxy');
app.use(cookieParser());
app.use(bodyParser.json()); // support json encoded bodies
app.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies
//Configure express app settings
app.engine('handlebars', expressHandlebars({extname: '.hbs'}));
app.set('view engine', 'handlebars');
app.get('/', function(req,res){
var options = { uri : 'https://someother/internal/api', json : true };
httpClient(options)
.then(function(data){
var success = { data : data };
console.log(dns.getServers(), 'Ok!');
res.json(success);
})
.catch(function(err){
var failed = { error : err.message };
console.log(dns.getServers(),err.message);
res.status(400).json(failed);
});
});
app.listen(8080, function(){
console.log("app started");
});
Any thoughts on why Node wouldn't re-read the resolv.conf or why it would not use the secondary DNS server when it realized the first was not working is appreciated.
You have roughly 3 options.
Add more application servers if your app is stateless
Lower the timeout in resolv.conf to 1 with rotate if you have multiple dns servers
increase the number of processes equal to the number of logical cores
You could do all three. This is really just a performance issue.
Node.js doesn't use the system's DNS resolution
https://nodejs.org/api/dns.html#dns_implementation_considerations
I'm merging two little apps into one, that is supposed to be accessed via two subdomains. To do so I'm using the module "express-subdomain". I'm trying to use Passport so when a user logs in in the first app, he is logged in in both apps. However using req.isAuthenticated() I can indeed login in the "first" app, but then I'm not in the "second" one.
I'm searching for any solution to have a passport authentification in the first subdomain and being logged in in the second one, including keeping two disctinct apps if needed.
Assuming that passport is correctly configured for a local strategy, as well as the routers and the rest of the app. Here is what it looks like :
app.js
// <- requires etc
var passport = require('./configurePassport.js')(require('passport'));
var app = express();
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(expressSession({
secret: 'bestSecretEver',
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
// and others
var firstRouter = express.Router();
firstRouter.use('/public', express.static(__dirname + '/first/public'));
firstRouter.use(favicon(__dirname + '/first/public/favicon.ico'));
// <- setting first router's GET, POST etc
app.use(subdomain('sub1', firstRouter)); // for sub1.example.com
var secondRouter = express.Router();
secondRouter.use('/public', express.static(__dirname + '/second/public'));
secondRouter.use(favicon(__dirname + '/second/public/favicon.ico'));
// <- setting second router's GET, POST etc
app.use(subdomain('sub2', secondRouter)); // for sub2.example.com
Any idea ?
Look into where you're saving your cookies for authentication purposes. Make sure you have it saved to the root domain. ie: *.example.com and not sub1.example.com
I've been having problems trying to access stored session values! Once I've set the values and try access them from a new route, I get undefined! So basically I've got a login (POST) and in that request I set the session data, and then I have a show user details (POST) where I try and access the session data I've just stored.
Setup
// Setup express and needed modules #############################################
var express = require('express'),
session = require('express-session'),
cookieParser = require('cookie-parser'),
redis = require("redis"),
redisStore = require('connect-redis')(session),
bodyParser = require('body-parser');
var client = redis.createClient(), //CREATE REDIS CLIENT
app = express();
// Setup app
app.use(cookieParser('yoursecretcode'));
app.use(session(
{
secret: 'x',
store: new redisStore({
port: 6379,
client: client
}),
saveUninitialized: true, // don't create session until something stored,
resave: false // don't save session if unmodified
}
));
app.use(bodyParser.urlencoded({ extended: true}));
app.use(bodyParser.json());
app.set('trust proxy', 1) // trust first proxy
So as you've seen my setup, you know I'm using express sessions and Redis. Below is where I'm setting the session values! If I print out the session values here it works, but then If I try and access the session data in another route it returns undefined.
Routes
I send a http post request and set the session data:
router.route('/login/').post(function(req, res) {
req.session.userId = req.body.uId;
req.session.name = req.body.uName;
// THIS PRINTS OUT IF I TRY AND ACCESS THE SESSION DATA HERE
console.log("THIS PRINTS OUT --> " + req.session.name);
});
So now that the session values have been set, I can go access them right, no, I get undefined each time I try and log them out.
router.route('/user/printoutuserdetails').post(function(req, res) {
// THESE RETURN UNDEFINED
console.log(req.session.userId);
console.log(req.session.uName);
console.log("THIS PRINTS OUT --> " + req.session.name);
});
Does anyone have any idea what's happening? I've tried everything and looked everywhere and can't seem to find a way to get it to work!
Solved:
The reason this wasn't was because you're not suppose to use sessions when using a RESTFUL api.
I'm new to NodeJS. I am developing a REST API and using express-session to deal with sessions. So, to get the session ID I'm using
var sessionID = req.sessionID
This sessionID is generated from the server side. So, when I scale up to two or more servers, this is a problem. For example, if one server shuts down and the request is redirected to another server (Assuming I have a load balancer), a new session ID is generated. So, is there a way to retrieve the session ID from the client side?
Good question! Session management can be challenging to get up and running with - especially since to get up and running with any sort of sophisticated session management in node you need a ton of different packages, each with their own set of docs. Here is an example of how you can set up session management with MongoDB:
'use strict';
var express = require('express'),
session = require('express-session'),
cookieParser = require('cookie-parser'),
mongoStore = require('connect-mongo')(session),
mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/someDB');
var app = express();
var secret = 'shhh';
app.use(session({
resave: true,
saveUninitialized: true,
secret: secret,
store: new mongoStore({
mongooseConnection: mongoose.connection,
collection: 'sessions' // default
})
}));
// ROUTES, ETC.
var port = 3000;
app.listen(port, function() {
console.log('listening on port ' + port + '.')
});
This configuration gives you access to req.sessionID but now it should persists across app servers if the user's session cookie has not expired.
I hope this works!