Express server middleware execute twice? - node.js

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.

Related

Node js: getting an error Cannot GET /route when i use get method

When I use the "use" method my code works fine, but when I use the "get" it gives an error: "Cannot GET /route1".
My Code:
const express = require('express');
const app = express();
const expbs = require('express-handlebars');
const path = require('path');
const routes = require('./routes/handlers');
app.use(express.static('public'));
const hbs = expbs.create({
defaultLayout: 'main',
layoutsDir: path.join(__dirname, 'views/mainLayout'),
partialsDir: path.join(__dirname, 'views/pieces'),
});
app.engine('handlebars', hbs.engine);
app.set('view engine', 'handlebars');
app.get('/route1', routes);
app.listen(8080, () => {
console.log('Server is starting at port ', 8080);
});
I am new to node js, please tell me can i define routes with "get" method.
I believe your routes/handlers.js look something like this
var express = require('express');
var router = express.Router();
function greetUser(req, res){
res.send("Welcome dear user");
}
router.get("/", greetUser);
router.post("/", (req, res)=>{ res.send("user registered") });
module.exports = router
The problem here is this last line, this router object which is being exported works fine for app.use middleware, while .get or .post expects 2nd parameter to be a function
If you export this greetUser function from your router as well or receive this function from anywhere, this should start functioning well. Practically it would be
app.get("/route1", (req, res)=>{ res.send({status : true, message : "sample JSON"})})
If you are using router you coudn't use get method.
Here is the docs.
Only the handler has access to get method. app.use will add path to api route which point to get,post and etc.
You could only explicitly define a get as a standalone get route.
app.get('/route1', (req, res) => {
res.send("You have hit route1 - get");
});
When using router you could only include the router object as a parameter in app.use(path, routerObj) method.
app.get('/route1', routes);
woulde be app.use('/route1', routes);

How to configure Express app with Vue Router?

I'm building an Express based app that works as follows:
'/' static main site served by Express with pug templating engine
'/admin' admin panel handled by VueJS with Vue Router in history mode
At the moment if I go to '/admin/about' it works fine, but when I refresh the page it throws the 404 error. How do I configure the server to handle all admin routes ('/admin/xxx') with Vue Router but all main site routes with Express (as it currently does)?
I've tried using connect-history-api-fallback middleware but with no success.
app.js
const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const history = require('connect-history-api-fallback');
const adminRoutes = require('./routes/admin');
const publicRoutes = require('./routes/index');
app.set('view engine', 'pug');
app.set('views', 'views');
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(express.static(path.join(__dirname, 'public')));
app.use('/admin', adminRoutes);
app.use(publicRoutes);
app.use(history());
app.use((req, res, next) => {
res.status(404).render('404', {
pageTitle: 'Page Not Found'
});
});
app.listen(3000);
routes/index.js
const express = require('express');
const router = express.Router();
router.get('/', (req, res, next) => {
res.render('home/index', {
pageTitle: 'Lorem Ipsum',
path: '/'
});
});
module.exports = router;
routes/admin.js
const express = require('express');
const router = express.Router();
router.get('/', (req, res, next) => {
res.render('admin/index', {
pageTitle: 'Admin Panel',
path: '/'
});
});
module.exports = router;
Your current configuration handles just root path / for the admin SPA(so you get 404 on all admin pages except the root if you tries to refresh page). You can allow all admin urls to be "processed" by Vue app on client(even 404 errors) with /* instead of / in your route.
But there will be a problem with http status codes because (as you probably guessed) server will always return 200 for every route... but I think most of developers are ok with this and just showing some 404-page-component for user if there is no component matched the url.
If you want to see correct http codes in your browser for web consistency, debugging, project requirements or something - without SSR, you will have to repeat your client routes in back-end I think.

Socket.io connecting many times instead of just once

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.

NodeJs routes not working from inner page

I am trying to develop an application in NodeJs using express framework. My routing is working when I navigating from home to inner pages. But If I want to navigate from some inner page to homepage then it is not working.
Below is my app.js code.
const express = require('express');
const path = require('path');
const engines = require('consolidate');
const bodyParser = require('body-parser');
//declare all routers
var home = require(path.join(__dirname, "/routes/index"));
var myaccount = require(path.join(__dirname, "/routes/myaccount"));
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.engine('html', engines.handlebars);
var defaultViewPath = path.join(__dirname, "/views");
app.set('views', defaultViewPath);
app.set('view engine', 'html');
app.use('/', home);
app.use('/myaccount', myaccount);
Here if I have navigated from home to myaccount - Its working
But if I am navigating from myaacount to home - It reloads the same page.
Can anyone help me to resolve this issue.
To define routing using methods of the Express app object, use app.get() to handle GET requests
var express = require('express')
var app = express()
// When GET request is made to the homepage
app.get('/', function (req, res) {
res.render('home');
});
// When GET request is made to the myaccount
app.get('/myaccount', function (req, res) {
res.render('myaccount');
});
app.get('/myaccount/innerpage', function (req, res) {
res.send('Hello Inner Page');
});
//Page Not Found
app.use(function(req, res){
//render the html page
//res.render('404');
res.sendStatus(404);
});
Hope this could help you
use app.get and app.post Route Methods
app.get('/',function(req,res){
res.render('home');
});
app.get('/myaccount',function(req,res){
res.render('myaccount');
});
Or Create Router File For Home & myAccount
var express = require('express')
var router = express.Router()
router.get('/', function (req, res) {
res.send('Home Page')
})
module.exports = router
in Your app.js or index.js file , require route.js
var home = require('./route');
app.use('/', home)

Code breaks once I start adding files to my controllers folder - why?

I am using node, express, fs and a few other things to create my first MVC framework app. I am currently googling around to find out more about an error I was getting, but am not finding the clarity I am looking for. Right now, I am not getting errors when I keep all my code in my server.js file. But that is not what MVC is all about, so at some point I created a users_controller.js file began to move the following routes into it (all except the ('/') route). As soon as I did that, everything broke!
The error I get is => TypeError: undefined is not a function
The line being referenced is => route.controller(app);
here is the code:
var express = require('express');
var logger = require('morgan');
var path = require('path');
var exphbs = require('express-handlebars');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var session = require('express-session');
var cookieParser = require('cookie-parser');
var pg = require('pg');
var bcrypt = require ('bcrypt');
var fs = require('fs');
var app = express();
var db = require('./db.js');
app.listen(3000);
app.engine('handlebars', exphbs({defaultLayout: 'main', extname: 'handlebars'}));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'handlebars');
//app.use(session({ secret: 'app', cookie: { maxAge: 60000 }}));
app.use(session({
secret: 'app',
resave: true,
saveUninitialized: true
}));
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static('public'));
app.use(logger('dev'));
// look in url encoded POST bodies and delete it
app.use(methodOverride(function(req, res) {
if (req.body && typeof req.body === 'object' && '_method' in req.body) {
var method = req.body._method;
delete req.body._method;
return method;
}
}));
//says look in the controllers folder for these routes
// dynamically include routes (Controller)
fs.readdirSync('./controllers').forEach(function (file) {
if(file.substr(-3) == '.js') {
route = require('./controllers/' + file);
route.controller(app); ///// <================= error =======
}
});
////check if session does not exist
app.get('/', function (req, res) {
if(!req.session.name) {
res.redirect('/loginform');
} else {
res.send("WELCOME BACK" + req.session.name);
}
});
///////renders login form if not logged in
app.get('/loginform', function (req, res) {
res.render('login');
});
///authenticates a login
app.post('/login', function (req, res){
db.findByColumn('users', 'username', req.body.name, function (data){
console.log(data);
bcrypt.compare(req.body.password, data[0].password_digest, function (err, result){
res.session.currentUser = req.body.name;
res.send('You\'re logged in '+ req.body.name + ' Be kind.');
});
res.redirect('/home');
});
});
///render home page once logged in
app.get('/home', function (req, res){
res.render('home');
});
//////register form
app.get('/register', function (req, res){
res.render('register');
});
After spending a bunch of time trying to figure out why I was getting the error, I moved it back into the server file. But I still got the error. So I deleted the users_controller.js file (making the controllers folder empty again), and everything worked again! So it seems the minute I put a file in the controllers folder, even an empty file, my code breaks. Hmmm.
My guess it that since fs is telling my server to look in the controllers folder for it's routes, as long as there are no files in there, it will look back to server.js for routes. But if there are, it looks there first (is this correct logic?). With that said, I have a couple questions:
1) Why is it breaking when I throw these routes in what 'seems' like the appropriate place, a controller file inside the controllers folder? After all, the controllers folder is where the routes SHOULD be coming from, right?
Once this all sorted out...
2) Best Practice: I figured the forms are dealing with users so I would put them in the user controller - but would it be better practice to make a forms_controller.js?
All input is appreciated ;)
There was an underscore in my filename (forms_controller.js) that was throwing the error.

Resources