I was looking at this Nodejs express Guthub repo. The production strack trace leak prevention is done using:
// development error handler
// will print stacktrace
if (!isProduction) {
app.use(function(err, req, res, next) {
console.log(err.stack);
res.status(err.status || 500);
res.json({'errors': {
message: err.message,
error: err
}});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.json({'errors': {
message: err.message,
error: {}
}});
});
I do not understand why the production strack trace middleware does not have to be inside the else condition
In the example you shared, an else block would probably make things a bit more clear, but it's not strictly needed. If isProduction is truthy, the error handling middleware inside the if block will handle the error. Since it does not call next(err); to pass the request to the next middleware, control will not be passed to the following "production" error-handling middleware. The response is sent and Express is done handling this particular request.
If isProduction is falsey, obviously the "development" middleware is not ever registered with Express and all errors will be handled in the "production" error-handler.
The above example, however, would break down if you needed to add another error-handling middleware after the "production" error-handler or something.
More Details
In Express, middlewares are run sequentially in the order in which they were registered and control is passed to the next middleware by using the calling the next parameter. See the documentation here.
Error handling middleware, like the ones posted in your example, work the same way. The error will reach these middlewares because a previous middleware called next and passed an error like so: next(new Error('Something went wrong));.
Related
The express doc says:
Note that the default error handler can get triggered if you call
next() with an error in your code more than once, even if custom error
handling middleware is in place.
I think it means if we call next(error) inside our custom error handler, then the control passes on to next error handler (which may be the express' default one if we already has not registered more custom error handlers).
Is my understanding correct?
Yes, you have understood it correctly. However, it is not useful to call the default error handler inside the custom error handler as the only purpose of the custom error handler is to send the errors to the user according to you i.e. in your format.
You can implement a custom global error handler by defining an error-handling middleware after all the app.use calls and in the callback function, you can create your own logic like sending different errors in dev or prod environment. You can also set up different user-friendly messages.
app.use(function (err, req, res, next) {
err.statusCode = err.statusCode || 500;
err.status = err.status || 'error';
if (process.env.NODE_ENV === 'development') {
// a custom function for sending dev errors
sendErrorDev(err, res);
} else if (process.env.NODE_ENV === 'production') {
// logic for creating different user-friendly errors
sendErrorProd(error, res);
}
})
And in both sendErrorDev and sendErrorProd functions, you can send the errors by the res object.
So , I am trying to implement CSRUF in express and I want to have custom errors thrown instead of the default error handling of the middleware CSRUF example here.
The CSRF implemntetion is working correctly and when the token is invalid,an error is thrown in console and a response with a 403 status is send to browser.
I do not want the error to be handled by default.
When I create a custom error handler middleware as below,
function (err,req, res, next) {
console.log("reached")
if (err.code !== 'EBADCSRFTOKEN') return next(err)
console.log("Not working")
// handle CSRF token errors here
res.status(500)
res.send('form tampered with')
}
It appears that the middlware is not being implemented as the default error for CSRUF is being thrown.
Intrestingly,I noticed that when i have a custom middeware with an err parameter,the middleware appears to be ignored by the app.
Example(This works)
function (req, res, next) {
console.log("This is some middleware") //Console outputs
next()
}
However,When I add a err or error parameter to the function as below,it appears as though the middleware is not being used
function (req, res, next) {
console.log("This is some middleware.Err parameter has been passed") //Nothing is output to console
next()
}
I have read the Express error handling documentation and done as required but i still face the error,What could be the issue and how do i handle such.
I finally figured it out.
When I place the error handler middleware just after the CSRUF everything works i.e
app.post(route,middleware1,errorhandler,(req,res)={
//Any errors from middleware1 will now be catched by the errorhandler instead of the default error handler
//Some code here
})
The location of the errorhandler appears to play a big role
Following a generated template for express. In the app.js there is a following snippet
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
Per my understanding, the middleware will run in order from app.use('/users', users) to 404 handler to error handler. My question is how will it be possible to reach error handler and execute this line res.status(err.status || 500); ? Wont every failed request be passed through 404 handler first and therefor getting the status code of 404? Please let me know if I am missing something! Thank you
No, it won't. If you look at these event handlers declarations you'll see that error handler for unhandled error, has an additional err parameter:
app.use(function(req, res, next) {
app.use(function(err, req, res, next) {
Error-handling middleware always takes four arguments. You must provide four arguments to identify it as an error-handling middleware function. Even if you don’t need to use the next object, you must specify it to maintain the signature. Otherwise, the next object will be interpreted as regular middleware and will fail to handle errors. For details about error-handling middleware.
So, when the route is not found, the last declared middleware is calling, it's 404 error handler.
But when you call next with error: next(err) or your code throws an error, the last error handler is calling.
System error should be handled before 404
app.use('/users', users);
// error handler
app.use(function(err, req, res, next) {
// No routes handled the request and no system error, that means 404 issue.
// Forward to next middleware to handle it.
if (!err) return next();
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
// catch 404. 404 should be consider as a default behavior, not a system error.
app.use(function(req, res, next) {
res.status(404);
res.render('Not Found');
});
Wont every failed request be passed through 404 handler first and therefor getting the status code of 404?
No, the 404 route is just a standard middleware and usually wired up last, meaning if no other routes handle the request they will eventually hit the 404.
The 500 is a special type of middleware, you'll notice it has 4 parameters (first one being an error param). This middleware is invoked as soon as you call next with an error, or any sort of data for that matter.
See the docs
Something to note for anyone else that stumbles around this post.
Your last middleware to be invoked (if none gets invoked) - will be 404, it doesn't take an err as its middleware parameter. Hence, you can't/shouldn't try to catch the 404 before any other middleware. So your last middleware should be without the err parameter like the example below and of course, should be at the bottom of your application stack.
//at the botton of your app.js
// catch 404.
//no err parameter
app.use(function(req, res, next) {
res.render("404Page"{
url: req.url
});
});
If you want to catch your errors before it goes to this handler use a (err, req, res, next) before this middleware.
I am trying to setup error handling for my express app and running into the following problem.
I defined an error middleware and add it as the last middleware:
// error handler
app.use(function(err, req, res, next) {
console.log('JUST TESTING. ERROR HANLDER HAS BEEN CALLED...');
next(err);
});
Now I would expect this middleware to be called whenever an error occurs:
app.get('/datenschutz', function(req, res, next){
return next(new Error('Just testing')); // handle everything here
});
However my middleware is never called! The browser does display the stack trace however.
This seems that there is another middleware that is catching this error and processing it before I can do anything about it.
The problem is that I have no clue where this middleware could be defined, as I have a very simple setup:
// setup ssl for local testing
var
app = express();
app.
use(express.static(__dirname + '/public')).
use(express.bodyParser()).
use(express.cookieParser());
Why is my error handling middleware not being called?
Where is this 'default' error handling taking place?
Thanks!
* EDIT *
I see that the middleware is indeed working. However this is the case if I call it from another middleware function.
However it is not being invoked if the error occurs inside a function defined as an express route (GET, POST, etc..). This is very strange.
If I add my error middleware to the route callbacks it then works:
app.get('/testError', function(req, res, next){
return next(new Error('Just testing')); // handle everything here
}, function(err,req,res,next) {
console.log('This error handler is called!!');
return next();
});
* EDIT 2 - FOUND ACCEPTABLE WORKAROUND **
I am surprised it has to be done this way. As I had read many entries/questions about error handling in express and never found this possibility mentioned.
However it seems that if an error ocurrs inside a route callback regular error middleware handlers will not pick it up. You will need to define an error handler at route level.
app.all('*', function(err,req,res,next) {
console.log('This is a global error handler at route level....');
return next(err);
});
I had this problem as well, but I couldn't figure out why it wasn't working even though I set my error handler after the app.user(app.router). As it turns out, I already had an error handler that I wasn't aware of.
Specifically, if you use the express cli to generate an app like I did, it will automatically add in this in:
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
Unfortunately for me, I added a bit more middleware to my app, which consequently obscured this statement and thus prevented my custom error handler from being called.
Simply remove that and then it should work properly.
On a side note, I should mention that the original solution still worked - even with the app.use(express.errorHandler()).
app.all('*', function(err,req,res,next) {
console.log('This is a global error handler at route level....');
return next(err);
});
Updated answer for Express 4 users from the Express 4 docs. See example from docs below. Note that app.router is deprecated and no longer used. I also added a dummy route to make the ordering clear:
"You define error-handling middleware last, after other app.use() and routes calls; For example:
var bodyParser = require('body-parser');
app.use(bodyParser());
app.get('/', function(req, res) {
res.send('hello world');
})
app.use(function(err, req, res, next) {
// logic
});
"
EDIT 2 (sabtioagoIT) works. But just for those who missed it, emostar's solution also works.
I understood to move the error handling 'use' call to the end, but there seems to be an easier option as emoster suggests, use app.router (before the error handling 'use' call).
instead of making
app.get('/datenschutz', function(req, res, next){
return next(new Error('Just testing')); // handle everything here
});
you can install express-async-errors
and just make
app.get('/datenschutz', function(req, res){
throw new Error('Just testing');
});
it works as expected
I'm developing an express app.
I currently have the following in my server.js
process.on('uncaughtException', function (err) {
console.log( "UNCAUGHT EXCEPTION " );
console.log( "[Inside 'uncaughtException' event] " + err.stack || err.message );
});
Which stops the server crashing every time there's an error, however, it just sits there...
is it possible to instead of console.log, to send a 500 error page with the error details?
I don't think you can from within the uncaughtException do a response since that could happen even when there is no request occurring.
Express itself provides a way to handle errors within routes, like so:
app.error(function(err, req, res, next){
//check error information and respond accordingly
});
Per ExpressJS Error Handling, add app.use(function(err, req, res, next){ // your logic }); below your other app.use statements.
Example:
app.use(function(err, req, res, next){
console.log(err.stack);
// additional logic, like emailing OPS staff w/ stack trace
});