Express Middleware flow - node.js

Consider the following Express app:
const express = require('express')
const app = express()
app.use((req, res, next) => {
console.log('\n\nALWAYS')
next()
})
app.get('/a', (req, res) => {
console.log('/a: route terminated')
res.send('/a')
})
app.use((req, res) => {
console.log('route not handled')
res.send('404 - not found')
})
app.listen(3000, () => {
console.log('listening on 3000')
})
Visit /a console result:
ALWAYS
/a: route terminated
ALWAYS
route not handled
Can somebody explain why is that there is another middleware log? I was expecting only 2 lines of console log. Instead
ALWAYS
route not handled
has been logged.

This is a very common point of confusion. The likely cause is that you went to /a in the browser and the browser made two requests. One for /favicon.ico and one for /a (that's what browsers do when you go to a new site they haven't previously cached the favicon for - the little glyph they display that represents the web site in some places in the browser).
If you log the request URL in your middleware and in your 404 handler, you will see the details of what is happening:
const express = require('express')
const app = express()
app.use((req, res, next) => {
console.log('\n\nRequest for: ', req.url);
next();
})
app.get('/a', (req, res) => {
console.log('/a: route terminated')
res.send('/a')
})
app.use((req, res) => {
console.log('route not handled for ', req.url);
res.send('404 - not found');
});
app.listen(3000, () => {
console.log('listening on 3000')
})

Related

Why errorHandler middlewear is getting called 2 time in express?

const express = require('express')
const app = express();
function middleWear1(req, res, next) {
throw Error()
}
function errorHandler(err, req, res, next) {
console.log("error handled");
res.end("error occured at server")
}
app.use(middleWear1)
app.use(errorHandler)
app.get('/', middleWear1)
app.listen(8000, () => {
console.log("server is listening");
})
when I do localhost:8000 I get "error handled" printed two times in NodeJS terminal.
can some one explain why is it happening?
Assuming you requested localhost:8000 through your web-browser, your browser will not only load http://localhost:8000/ but http://localhost:8000/favicon.ico as well. This is default browser behaviour.
Now, since you've setup middleWear1 to run for every request and the two requests are sent to your server, error handled gets printed twice to the console.
To answer you question from the comment:
In order to prevent middleWear1 running for all requests and only for your / route, you can do:
const express = require('express')
const app = express()
function middleWear1(req, res, next) {
throw Error()
}
function errorHandler(err, req, res, next) {
console.log("error handled");
res.end("error occured at server")
}
app.get('/', middleWear1)
app.use(errorHandler)
app.listen(8000, () => {
console.log("server is listening");
})

Error handling problem with Nodejs and Express

I'm trying to handle errors produced in a Nodejs with Express app. I'm following Express error-handling guide but the errors didn't catched, and nothing appears on console and browser simply show Cannot GET /abc when request the incorrect url http://localhost:3000/abc
const express = require("express")
const app = express()
const port = 3000
const config = require("./config.js");
function logErrors (err, req, res, next) {
console.error(err.stack)
next(err)
}
function errorHandler (err, req, res, next) {
res.status(500)
res.render("error", { error: err })
}
app.all("/", function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
});
app.get("/favicon.ico", (req, res) => res.status(204));
app.use(express.static("public"))
app.use("/zips/:idReq", express.static("zips"))
const generateZip = require("./generateZip")
const fmeForm = require("./fmeForm")
app.get("/", function (req, res) {
res.send("Hello World !")
})
app.use("/generateZip", generateZip)
app.use("/downloadForm", fmeForm)
app.use(logErrors)
app.use(errorHandler)
app.listen(port, () => console.log(`${config.nameServer} App listening on port ${port}`))
Any idea?
You need to include a common route handler to invoke error handling method at last
app.all('*', function (req, res, next) {
// Either invoke error handler method by raising new error
next(new Error('page not found'));
// Or simply return the response
res.status(404).send('page not found')
})

How to call app.get() after app.use() node js express? Pass request from app.use() to app.get()

const express = require('express');
const app = express();
app.use('/', (req, res,next) => {
res.send('Bid Request GET');
});
app.get('/', (req, res) => {
res.send('Bid T');
});
app.listen(3000, () => console.log('app listening on port 3000!'))
I am beginner in node js. When I run the code it only shows app.use() response not app.get() response.
I am confused. i tried next() method also, but not working. how to solve this?
Main reason behind this is because you've already sent the response here:
app.use('/', (req, res,next) => {
res.send('Bid Request GET');
});
You can only send one response per request.
Each app.use middleware is a function with access to request, response, next parameter. when next function is invoked, it executes the middleware succeeding the current middleware.
You can also pass data from one middleware to another by creating variable in request or response. For Ex.
app.use('/', (req, res, next) => {
if(req.body.token !== 'abc') return res.sendStatus(503)
let someData = () => { .... SomeFunctionCode ... }
req.myVarible = someData // or res.myVariable = someData or anything
next()
})
But the recommended way of passing value is through res.locals.myVariable
Here is full example:
app.use('/', (req, res, next) => {
if(req.body.token !== 'abc') return res.sendStatus(503)
let someData = () => { .... SomeFunctionCode ... }
req.locals.myVarible = someData
next()
})
app.get('/', (req, res) => {
res.send(res.locals.myVariable)
})

NodeJS Express middleware goes to next one without next()

I am trying to learn Express for NodeJS but I came across this:
I am trying to add 2 middlewares depeding on url, so on the /user to do something and on root to do something different. However the root middleware is always called even if i dont use next() and if i access the "/" url, the root middleware is called twice.
const express = require('express');
const app = express();
app.use('/user', (req, res, next) => {
console.log('In user middleware ');
res.send('<h1>Hello from User page</h1>');
});
app.use('/', (req, res, next) => {
console.log('In slash middleware !');
res.send('<h1>Hello from Express !</h1>');
});
app.disable('etag');
app.listen(3000);
it should be get or post not use
-get or post are routes
-use is middleware function
check this
const express = require('express');
const app = express();
app.get('/user', (req, res, next) => {
console.log('In user middleware ');
res.send('<h1>Hello from User page</h1>');
});
app.get('/', (req, res, next) => {
console.log('In slash middleware !');
res.send('<h1>Hello from Express !</h1>');
});
app.disable('etag');
app.listen(3000);
From an issue at GitHub.com
https://github.com/expressjs/express/issues/3260
Hi #davidgatti my "root path middlware" I assume you are talking about
nr_one. If so, yes, of course it is executed on every request; app.use
is a prefix-match system. Every URL starts with /, so anything mounted
at / will of course get executed :)
Okay, I can't confirm this but I suspect from the tutorial you are following you might be missing a line.
As you said, app.use is a middleware which will be added to all the route
So when you load say some url where you expect the middleware then it won't know about the request type (post, put, delete or get request).
Any alternate for this could be to try something like this
app.use('/user', (req, res, next) => {
if (req.method === 'GET') {
console.log('In user middleware ');
res.send('<h1>Hello from User page</h1>');
}
});
Again, Just check and compare his code thoroughly
Adding this link from Justin's answer for reference
In order to avoid such a problem, you have to use the return keyword.
When you send a file to the server, use return.
Try the following code,
const express = require('express');
const app = express();
app.use('/user', (req, res, next) => {
console.log('In user middleware ');
return res.send('<h1>Hello from User page</h1>');
});
app.use('/', (req, res, next) => {
console.log('In slash middleware !');
return res.send('<h1>Hello from Express !</h1>');
});
app.disable('etag');
app.listen(3000);
At line 13 and 8, I used the return keyword.
So when you make http://localhost:3000/ request, you will receive
Hello from Express !
And whenever you make http://localhost:3000/user request, you will receive
Hello from User page

How can I get Express.js to 404 only on missing routes?

At the moment I have the following which sits below all my other routes:
app.get('*', function(req, res){
console.log('404ing');
res.render('404');
});
And according to the logs, it is being fired even when the route is being matched above. How can I get it to only fire when nothing is matched?
You just need to put it at the end of all route.
Take a look at the second example of Passing Route Control:
var express = require('express')
, app = express.createServer();
var users = [{ name: 'tj' }];
app.all('/user/:id/:op?', function(req, res, next){
req.user = users[req.params.id];
if (req.user) {
next();
} else {
next(new Error('cannot find user ' + req.params.id));
}
});
app.get('/user/:id', function(req, res){
res.send('viewing ' + req.user.name);
});
app.get('/user/:id/edit', function(req, res){
res.send('editing ' + req.user.name);
});
app.put('/user/:id', function(req, res){
res.send('updating ' + req.user.name);
});
app.get('*', function(req, res){
res.send('what???', 404);
});
app.listen(3000);
Alternatively you can do nothing because all route which does not match will produce a 404. Then you can use this code to display the right template:
app.error(function(err, req, res, next){
if (err instanceof NotFound) {
res.render('404.jade');
} else {
next(err);
}
});
It's documented in Error Handling.
I bet your browser is following up with a request for the favicon. That is why you are seeing the 404 in your logs after the 200 success for the requested page.
Setup a favicon route.
You can this at the end of all routes,
const express = require('express');
const app = express();
const port = 8080;
// All your routes and middleware here.....
app.use((req, res, next) => {
res.status(404).json({
message: 'Ohh you are lost, read the API documentation to find your way back home :)'
})
})
// Init the server here,
app.listen( port, () => {
console.log('Sever is up')
})
Hope it helpful, I used this code in bottom of routes
router.use((req, res, next) => {
next({
status: 404,
message: 'Not Found',
});
});
router.use((err, req, res, next) => {
if (err.status === 404) {
return res.status(400).render('404');
}
if (err.status === 500) {
return res.status(500).render('500');
}
next();
});
You can use this
const express = require('express');
const app=express();
app.set('view engine', 'pug');
app.get('/', (req,res,next)=>{
res.render('home');
});
app.use( (req,res,next)=>{
res.render('404');
})
app.listen(3000);
I wanted a catch all that would render my 404 page only on missing routes and found it here in the error handling docs https://expressjs.com/en/guide/error-handling.html
app.use(function (err, req, res, next) {
console.error(err.stack)
res.status(404).render('404.ejs')
})
This worked for me.
Very simple you can add this middleware.
app.use(function (req, res, next) {
//Capture All 404 errors
res.status(404).render("404.ejs")
})
404 error in a service is typically used to denote that the requested resource is not available. In this article we will see how to handle 404 error in express.
We need to handle the Error and Not-Found collectively as
Write two separate middleware for each,
// Import necessary modules
const express = require('express');
// Create a new Express app
const app = express();
// Define routes and middleware functions
app.get('/', (req, res) => {
res.send('Hello World!');
});
// Catch 404 Not Found errors and forward to error handler
app.use((req, res, next) => {
const error = new Error('Not Found');
error.status = 404;
next(error);
});
// Error handler middleware function
app.use((err, req, res, next) => {
// Set status code and error message based on error object
res.status(err.status || 500);
res.send({
error: {
message: err.message
}
});
});
// Start the server
app.listen(3000, () => {
console.log('Server started on port 3000');
});

Resources