Socket.io connecting many times instead of just once - node.js

I have build this app, with express.js, its a basic webapp, but now i want to add a simple messaging system.
I already had built my express app and server like this:
const app = require('./app');
app.set('port', process.env.PORT || 7777);
const server = app.listen(app.get('port'), () => {
console.log(`Express running → PORT ${server.address().port}`);
But as I follow this tutorial on socket.io: https://socket.io/get-started/chat/
I changed my start.js to this, to use socket.io:
const app = require('./app');
app.set('port', process.env.PORT || 7777);
const server = app.listen(app.get('port'), () => {
console.log(`Express running → PORT ${server.address().port}`);
});
const io = require('socket.io').listen(server);
io.on('connection', function(socket){
console.log('a user connected');
});
It says on the tutorial that when a user signs up i should see a console log saying: a user is connected
However I get one log per frame... not just one per connected user.
Is this behaviour correct with the changes i made.. or should i still be getting still just one log per connected user?
Im also using pug as my templating language, and i have, at the end of my layout file this:
block scripts
script(src=`https://maps.googleapis.com/maps/api/js?key=${process.env.MAP_KEY}&libraries=places`)
script(src="/dist/App.bundle.js")
script(src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js")
script.
const socket = io()
App.js:
const express = require('express');
const session = require('express-session');
const mongoose = require('mongoose');
const MongoStore = require('connect-mongo')(session);
const path = require('path');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const passport = require('passport');
const promisify = require('es6-promisify');
const flash = require('connect-flash');
const expressValidator = require('express-validator');
const routes = require('./routes/index');
const helpers = require('./helpers');
const errorHandlers = require('./handlers/errorHandlers');
require('./handlers/passport');
// create our Express app
const app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views')); // this is the folder where we keep our pug files
app.set('view engine', 'pug'); // we use the engine pug, mustache or EJS work great too
// serves up static files from the public folder. Anything in public/ will just be served up as the file it is
app.use(express.static(path.join(__dirname, 'public')));
// Takes the raw requests and turns them into usable properties on req.body
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// Exposes a bunch of methods for validating data. Used heavily on userController.validateRegister
app.use(expressValidator());
// populates req.cookies with any cookies that came along with the request
app.use(cookieParser());
// Sessions allow us to store data on visitors from request to request
// This keeps users logged in and allows us to send flash messages
app.use(session({
secret: process.env.SECRET,
key: process.env.KEY,
resave: false,
saveUninitialized: false,
store: new MongoStore({ mongooseConnection: mongoose.connection })
}));
// // Passport JS is what we use to handle our logins
app.use(passport.initialize());
app.use(passport.session());
// // The flash middleware let's us use req.flash('error', 'Shit!'), which will then pass that message to the next page the user requests
app.use(flash());
// pass variables to our templates + all requests
app.use((req, res, next) => {
res.locals.h = helpers;
res.locals.flashes = req.flash();
res.locals.user = req.user || null;
res.locals.currentPath = req.path;
next();
});
// promisify some callback based APIs
app.use((req, res, next) => {
req.login = promisify(req.login, req);
next();
});
// After allllll that above middleware, we finally handle our own routes!
app.use('/', routes);
// If that above routes didnt work, we 404 them and forward to error handler
app.use(errorHandlers.notFound);
// One of our error handlers will see if these errors are just validation errors
app.use(errorHandlers.flashValidationErrors);
// Otherwise this was a really bad error we didn't expect! Shoot eh
if (app.get('env') === 'development') {
/* Development Error Handler - Prints stack trace */
app.use(errorHandlers.developmentErrors);
}
// production error handler
app.use(errorHandlers.productionErrors);
// done! we export it so we can start the site in start.js
module.exports = app;

The problem was that i had opened multiple tabs with the app, therefore all the logs where from other tabs being connected.

Related

ReferenceError: done is not defined

const express = require('express');
const cookieParser = require('cookie-parser');
const port = 8000;
const app = express();
const expressLayout = require('express-ejs-layouts');
const db = require('./config/mongoose')
// used for session cookie
const session = require('express-session')
const passport = require('passport')
const passportLocal = require('./config/passport-local-strategy')
app.use(express.urlencoded())
app.use(cookieParser());
// where to look static files like css,js
app.use(express.static('./assets'))
// this line must be above the routes line (line no. 11 in this case) because in the routes all the views are going to be render and before that we have to tell to the browser the layout
app.use(expressLayout)
// extract style and scripts from sub pages into the layout
app.set('layout extractStyles', true);
app.set('layout extractScripts', true);
// set up the view engine
app.set('view engine', 'ejs');
app.set('views', './views');
app.use(session({
name: 'iFacebook',
// TODO change the secret before deployment in production mode
secret: 'Coder',
saveUninitialized: false,
resave: false,
cookie: {
maxAge : (1000*60*100)
}
}))
app.use(passport.initialize());
app.use(passport.session())
// use express router
// require('./routes/index) is similar to require('./routes) in this case, it by default fetch routes
app.use('/', require('./routes/index'))
app.listen(port, (err) => {
if (err) {
console.log(`Error in running the server : ${err}`);
}
console.log(`Server is listening at ${port}`);
})
I am using passport and passport-local strategy and this error comes and even i did not know from which file this error comes. I am sharing the index.js file code which is the server file. This is the first time i am using this even on the documentation i did not found anything

Express server middleware execute twice?

After trying to log some data on index file. I found my express server execute twice. Why do i get this error/bug?
Running Node 12.13.0 LTS, Express 4.17.1 and latest packages versions by the date of this post. I’ve tried on commenting some parts of code and always seem to end up running twice.
My app.js code:
const express = require('express');
const expressLayouts = require('express-ejs-layouts');
const path = require('path');
const bodyParser = require('body-parser');
const favicon = require('serve-favicon');
const app = express();
// ENV Variables
require('dotenv').config();
const PORT = process.env.PORT;
// Authentication Packages
const session = require('express-session');
const passport = require('passport');
// Middlewares
app.use(favicon(path.join(__dirname,'public','images','favicon.ico')));
app.use(bodyParser.urlencoded({extended: false}));
app.use(express.json());
app.use(session({
secret: 'GBR6N7^?5Xx-Ldqxf&*-Hv$',
resave: false,
saveUninitialized: false,
//cookie: { secure: true }
}));
app.use(passport.initialize());
app.use(passport.session());
// View Engine
app.use(expressLayouts);
app.use(express.static(path.join(__dirname, 'public')));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// Routes
app.use('/', require('./routes/index'));
// Controllers
app.use('/profile', require('./routes/profile'));
app.use('/products', require('./routes/products'));
app.use('/bookmarks', require('./routes/bookmarks'));
// Catch 404
app.use((req, res) => {
res.render('pages/404');
});
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
and my index.js code:
const express = require('express');
const router = express.Router();
// Official pages
router.get('/', (req, res) => {
// THIS IS THE CODE I GET TWICE ON CONSOLE
console.log(req.user);
console.log(req.isAuthenticated());
// THIS IS THE CODE I GET TWICE ON CONSOLE
res.render('pages/index');
});
router.get('/about', (req, res) => {
res.render('pages/about');
});
router.get('/features', (req, res) => {
res.render('pages/features');
});
// Footer pages
router.get('/terms', (req, res) => {
res.render('pages/terms');
});
router.get('/refunds', (req, res) => {
res.render('pages/refunds');
});
module.exports = router;
Also i have those two functions on my profile.js (for passport.js):
passport.serializeUser((userId, done) => {
done(null, userId);
});
passport.deserializeUser((userId, done) => {
done(null, userId);
});
I get those results twice:
console.log(req.user);
console.log(req.isAuthenticated());
Output (Executed twice!):
undefined
false
undefined
false
and I expect one:
undefined
false
Due to how Express routing works, the path / will match / and /about and /favicon.ico etc. This is because Express supports not just endpoint routing but also path mounting. In other words, express supports things like this:
const app = express();
const route = express.Router();
route.get('/world', (req, res) => { res.send('hello') });
app.get('/hello', route); // mounts world to hello
// so we can access /hello/world
In order to support the feature above, express needs to interpret paths such as /hello to mean both /hello and /hello/anything/else. It needs to treat it as both the endpoint and potentially just a path leading to an endpoint.
This means that if you have a path:
app.get('/', () => {});
It will also trigger if the browser requests /favicon.ico. And browsers request favicon.ico to draw the tiny icon in the browser tab. This is why your route is triggered twice.
A few things to keep in mind when writing Express routes/controllers:
Make sure that the / path is last because otherwise it will also respond to requests to all your other paths.
If you are using express.static() make sure it is set up before the / path. Yes, the first rule above should also cover this but I see this issue often enough that it merits its own point.
In your case you can possibly fix the issue by simply creating a favicon.ico icon and saving it in the static (public) folder.

receiving 404 not found when calling axios with node and heroku

my react app landing page calls and axios.get on component did mount. I have no issues when running my page locally, however when I deploy with heroku, my axios call returns "404 not found nginx". It feels like a simple fix, although I cant seem to find any threads online that apply to my issue. my server.js is configured as follows
const express = require("express");
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
const routes = require('./routes');
const dotenv = require("dotenv");
var request = require('request'); // "Request" library
var cors = require('cors');
var querystring = require('querystring');
var passport = require('passport');
var flash = require('connect-flash');
var session = require('express-session');
var morgan = require('morgan');
// var configDB = require('./config/database.js');
require('./config/passport')(passport); // pass passport for configuration
// const fs = require("fs");
var client_id = process.env.DB_SPOTIFY_CLIENT_ID; // Your client id
var client_secret = process.env.DB_SPOTIFY_CLIENT_SECRET; // Your secret
var redirect_uri = process.env.DB_REDIRECT_URI; // Your redirect uri
dotenv.config();
// const port = process.env.PORT || 3030;
const port = 3030
const app = express();
app.use(morgan('dev')); // log every request to the console
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.set('view engine', 'ejs'); // set up ejs for templating
// required for passport
app.use(session({ secret: 'ilovescotchscotchyscotchscotch' })); // session secret
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash()); // use connect-flash for flash messages stored in session
// Demo middleware to play with error handling
app.use((req, res, next) => {
const startTime = Date.now();
console.log("Request Time: " + startTime);
console.log(`${req.method} ${req.path}`);
// Request returns 500, default handler returns error
// as html with stack trace in dev, does not terminate server process.
//throw new Error("Bazinga!");
next();
// Request returns 500, default handler returns error as html showing stack trace,
// and terminates server process with error ERR_HTTP_HEADERS_SENT.
//next(new Error("Bazonga!"));
const endTime = Date.now();
console.log(
"Response Time: " + endTime + " Elapsed: " + (endTime - startTime)
);
// Request goes through, error is written to log.
//throw new Error("Bazunga!");
});
// app.use("/node-api/server.js/schedule", (req, res, next) => {
// fs.readFile("data/schedule.json", (err, data) => {
// if (err) {
// // If err, then
// next(err);
// } else {
// res.type("json").send(data);
// }
// });
// });
// routes ======================================================================
require('./routes/LoginRegister.Routes')(app, passport); // load our routes and pass in our app and fully configured passport
app.use("/serverSideStuff/server.js", routes);
app.use((req, res) => {
res.status(404).send("<h2>The path is not valid</h2>");
});
app.listen(port, () => {
console.log(`Magic happens on port ${port}`);
});
you forgot to uncomment this line:
// const port = process.env.PORT || 3030;
and delete this one:
const port = 3030
process.env.PORT will be heroku port :)

PassportJS Multi-tenancy with ExpressJS

I tried to implement a solution where I have a single ExpressJS app and two Mongoose models for users, one for standard users and the other for administrators. I'm using passport-local-mongoose for the user models. However, I was having an issue where authentication would succeed but the user would not stay in session (req.user would be undefined). I thought that there would be a conflict having two Passport Local strategies with one ExpressJS app. I've been searching for examples and nothing is working. Please see my code below:
index.js
'use strict';
const express = require('express');
const bodyParser = require('body-parser');
const Passport = require('passport').Passport,
appPass = new Passport(),
adminPass = new Passport();
const mongoose = require('mongoose');
const cookieSession = require('cookie-session');
const path = require('path');
const keys = require('./config/keys');
require('./models/User');
require('./models/AdminUser');
require('./models/EM');
mongoose.Promise = global.Promise;
mongoose
.connect(keys.mongoURI)
.then(() => console.log('DB connection successful'))
.catch(err => console.error(err));
// Create new instances of express
const app = express();
const adminApp = express();
// View engine setup
adminApp.set('views', path.join(__dirname, 'views/admin'));
adminApp.set('view engine', 'pug');
// Tell express to use the body-parser middleware and to not parse extended bodies
adminApp.use(bodyParser.urlencoded({ extended: true }));
adminApp.use(bodyParser.json());
const AdminUser = mongoose.model('AdminUser');
adminPass.use(AdminUser.createStrategy());
adminPass.serializeUser(AdminUser.serializeUser());
adminPass.deserializeUser(AdminUser.deserializeUser());
adminApp.use(
cookieSession({
maxAge: 30 * 24 * 60 * 60 * 1000,
keys: [keys.adminCookieKey]
})
);
adminApp.use(adminPass.initialize());
adminApp.use(adminPass.session());
adminApp.use(express.static('public'));
require('./routes/adminRoutes')(adminApp);
adminApp.listen(5001, function(err) {
if (err) {
console.log(err);
}
console.log('Admin server started on port 5001');
});
// app.use(cors());
// View engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
// Tell express to use the body-parser middleware and to not parse extended bodies
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
const User = mongoose.model('User');
appPass.use(User.createStrategy());
appPass.serializeUser(User.serializeUser());
appPass.deserializeUser(User.deserializeUser());
app.use(
cookieSession({
maxAge: 30 * 24 * 60 * 60 * 1000,
keys: [keys.cookieKey]
})
);
app.use(appPass.initialize());
app.use(appPass.session());
app.use(express.static('public'));
require('./routes/authRoutes')(app);
require('./routes/portalRoutes')(app);
require('./routes/apiRoutes')(app);
if (process.env.NODE_ENV === 'production') {
// Express will serve up production assets
// like our main.js file, or main.css file!
app.use(express.static('client/build'));
// Express will serve up the index.html file
// if it doesn't recognize the route
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
}
const PORT = process.env.PORT || 5000;
app.listen(PORT, function(err) {
if (err) {
console.log(err);
}
console.log('Server started on port 5000');
});
module.exports = {
adminPass: adminPass,
appPass: appPass
};
adminRoutes.js
var Index = require('../index');
var admin = require('../controllers/AdminController.js');
module.exports = app => {
// route to admin dashboard page
app.get('/adminDB', admin.adminDB);
// route to admin login page
app.get('/adminLogin', admin.adminLogin);
// route for admin login action
app.post(
'/adminLogin',
Index.adminPass.authenticate('local'),
admin.adminDoLogin
);
// route for admin logout action
app.get('/adminLogout', admin.adminLogout);
};
When I run this, I get an error that authenticate can't be called on undefined. May be I'm more far off from the proper solution having gone this route but I have no idea how to fix the req.user problem using the previous approach. Does anyone know how to implement multi-tenancy, ideally with only one ExpressJS app?

Cannot GET when using forever with node and express

We are using NodeJS and Express in combination with forever. That worked fine, but now we had to update our NodeJS version and it all stops working.
We use angular with ui-routing for frontend routing so we have an static folder.
I can go to our homepage (/) and from there I can navigate to the whole site. But when I refresh an page or I go directly to an page (eg. /products) I get an
Cannot GET /products
error.
Node gives an 404 error.
When I run the script directly without forever everything works fine. As you can see we have 2 static folders configured in express. Before the update everything works fine.
We also use Apache to redirect custom domainnames to specific pages without changing the address in the browser, but that works fine (only shows the GET error instead of the page).
Anybody any idea how to solve this?
our app.js
var path = require('path');
var fs = require('fs');
// Return values from different config files will be added to this object so you can call config.[category].[property].
config = {};
// Save the app root directory to a global variable so it can be used in config files and other parts of the app. global.root is reserved, but global.path.root can be used without problems.
global.path = {root: path.resolve(__dirname)};
// Set environment and initialize environment-specific config variables
config.env = require(path.join(__dirname, 'config', 'env.config'));
// Set up database connection to use throughout the application
config.db = require(path.join(__dirname, 'config', 'db.config'));
// HTTP for development environment, HTTPS for production environment
var http = require('http');
var https = require('https');
// Set up debugging/logging for the development environment
var debug = require('debug')('http');
// Start the app using the Express settings/routines in express.config.
var app = require(path.join(__dirname, 'config', 'express.config'));
// Start GraphQL process
// require(path.join(__dirname, 'config', 'graphql.config'))(app);
var router = require(path.join(__dirname, 'config', 'routes.config'));
router(app);
// Running in production mode: HTTPS only
if(config.env.name === 'production') {
var credentials = {
privateKey: fs.readFileSync('privkey'),
certificate: fs.readFileSync('fullchain')
};
var server = https.createServer(credentials, app);
server.listen(4443);
server.on('error', onError);
server.on('listening', onListen);
var server2 = http.createServer(app);
server2.listen(8080);
// Running in development mode: HTTP only
} else {
var server = http.createServer(app);
server.listen(config.env.port);
server.on('error', onError);
server.on('listening', onListen);
}
//some listeners here
Our express.config.js
var path = require('path');
console.log('Initializing API...');
var express = require('express');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var compression = require('compression');
var morgan = require('morgan');
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);
var config = require(path.join(__dirname, 'db.config'));
// The GraphQL server implementation for Express by the Apollo team.
var graphqlExpress = require('graphql-server-express').graphqlExpress;
var graphiqlExpress = require('graphql-server-express').graphiqlExpress;
var OpticsAgent = require("optics-agent");
var passport = require('passport');
var app = express();
// Handle application/json requests
app.use(bodyParser.json({ limit: '50mb' }));
// Handle application/x-www-form-urlencoded requests (usually POST, PUT, etc.)
app.use(bodyParser.urlencoded({ extended: false, limit: '50mb' }));
app.use(cookieParser());
app.use(session({
store: new MongoStore({
url: 'mongodb://' + config.url + ':' + config.port + '/' + config.name
}),
secret: 'secret',
key: 'skey.sid',
resave: false,
saveUninitialized: false,
cookie : {
maxAge: 604800000 // 7 days in miliseconds
}
}));
app.use(passport.initialize());
app.use(passport.session());
require(path.join(__dirname, 'auth.config'))(passport); //Load passport config
app.use(function(req, res, next) {
req.resources = req.resources || {};
// res.locals.app = config.app;
res.locals.currentUser = req.user;
res.locals._t = function (value) { return value; };
res.locals._s = function (obj) { return JSON.stringify(obj); };
next();
})
// Use gzip compression (following the Express.js best practices for performance)
app.use(compression());
// Serve frontend and static files like stylesheets and images from the Express server
app.use(express.static(path.join(__dirname, '..', '..', 'app')));
app.use(express.static(path.join(__dirname, '..', '..', 'public')));
// Morgan logger (previously named express-logger)
app.use(morgan("dev"));
// Generate the GraphQL schema
var schema = require(path.join(__dirname, 'graphql.config'))().then(function(schema) {
/* Use Apollo Optics middleware for query optimization/tracing. */
OpticsAgent.instrumentSchema(schema);
app.use('/apiv2', OpticsAgent.middleware());
console.log('GraphQL schema generated.');
/* Return params object for Apollo GraphQL Server using a request handler function. */
app.use('/apiv2', graphqlExpress(function(req) {
return {
schema: schema,
debug: true,
context: {
opticsContext: OpticsAgent.context(req)
}
};
}));
app.use('/graphiql', graphiqlExpress({endpointURL: '/apiv2'}));
console.log('GraphQL started.');
/* Handle all other HTTP requests AFTER graphql server API endpoint and other routes are defined. */
app.use('*', express.static('app'));
});
// Always keep the errorHandler at the bottom of the middleware function stack!
// Returns a user-friendly error message when the server fails to fulfill the request
app.use(function(err, req, res, next) {
var status = 500, response = {message: 'An internal server error has occurred while trying to load this page. '};
console.error(err.stack);
res.status(status).json(response);
next(err);
});
module.exports = app;
Not really an solution to this problem, but we changed forever to PM2 (https://github.com/Unitech/pm2) and that program is doing his job fine!

Resources