I'm using a custom error page in Express, as explained here.
But when I do that, I only see the error message. I'd like to get hold of the same information as displayed in the default Express error handler (the stacktrace, etc.), so that I can:
Log it to the console (if I could leave the default in place for this, I'd be happy).
Display it on the error page, but only for localhost.
How do I do this?
This is a modified version from #generalhenry's answer. You can access the stack trace
in err.stack so you can pass it on your '500' view and do some fancy css styles on it.
app.use(function(err, req, res, next) {
if (err instanceof NotFound) {
res.render('errors/404');
} else {
res.render('errors/500', {error: err, stack: err.stack});
}
});
function NotFound() {
this.name = "NotFound";
Error.call(this, msg);
Error.captureStackTrace(this, arguments.callee);
}
// below all route handlers
// If all fails, hit em with the 404
app.all('*', function(req, res){
throw new NotFound;
});
Just use the error provided to the middleware
// Handle 500
app.use(function(error, req, res, next) {
console.error(error);
if (ISLOCALHOST()) {
res.json(error, 500);
} else {
res.send('500: Internal Server Error', 500);
}
});
Related
What is the advantage of catching errors and responding from within a middleware function like in example A.
Example A
function(req, res, next)
{
if (err) {
err.message = 'Not Found';
res.status(404).json(err);
return;
}
}
Versus passing the error to the error handling middleware like in example B.
Example B
function(req, res, next)
{
if (err) {
var err = new Error('Not Found');
err.status = 404;
next(err);
}
}
error handling middleware:
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.json({message: "error"});
});
Imagine you are piping the request through several functions to process it, and the error in one of the first functions is superficial. You can still process the request, but you need to send a warning or handle the error afterwards. Perhaps you want to gather all of the errors in the pipeline report them back. Example B allows this.
But imagine the error is critical, and you know you won't be able to proceed. In that case you, can't call next, because the next function won't know how to deal with a fundamentally broken request. Here is where example A comes in handy.
When I use domain.dispose() in Node.js expressjs based HTTP Server, the client making HTTP sees a response code of 0 (Could not get any response). If I remove domain.dispose() I receive 500 error with the desired error message. Below is my code
//Enable domains
app.use(function(req, res, next){
var createDomain = require('domain').create;
var domain = createDomain();
domain.add(req);
domain.add(res);
domain.run(function() {
next();
});
domain.on('error', function(e) {
//no further domain watch required
domain.dispose(); //if I remove this line status code of 500 is received on client, otherwise 0 or no response is received
next(e);
});
});
//Respond with 500 for Unhandled errors
app.use(function(err, req, res, next) {
// If the error object doesn't exists
if (!err) return next();
// Log it
req.log.error(err);
//console.error(err.stack);
try{
if(req.path && req.path.indexOf('/api/') === 0){
if(!res.headersSent){
console.log('responded with an error');
res.status(500).send({error: err.message});
console.log('responded with an error ACK');
}
return;
}
// Error page
res.status(500).render('500', {
error: err.stack
});
} catch(ex){
console.log('An error occured while responding 500');
req.log.error(ex);
}
});
Can anyone explain this or a better solution? Removing domain.dispose() may cause further exceptions, which may cause to re-enter the domain, and I do want to acknowledge client with the exception message as in my code.
This is expected behaviour of domains. Since you have explicitly added req and res to domain, so they are disposed as well. Don't use dispose, it does unexpected things. When you catch an error with domain the only sensible thing to do is to shutdown the process as quickly as possible.
I use express in node.js,and i want to custom 404 and 500 error page.
i write the code like below:
// Handle 404
app.use(function (req, res) {
res.send('404: Page not Found', 404);
});
// Handle 500
app.use(function (error, req, res, next) {
res.send('500: Internal Server Error', 500);
console.log(error);
});
it's right if 404 or error in background,but when there is a error in ejs(in a view),eg null or undefined ,it will show the detail error info..
such as:
Express
500 ReferenceError:
at eval (eval at (D:\node_workspace\study\node_modules\ejs\lib\ejs.js:237:14), :29:1117)
at eval (eval at (D:\node_workspace\study\node_modules\ejs\lib\ejs.js:237:14), :29:1593)
etc..
i really don't want to show such error page to users.. so,how can i config to avoid this?
U can use something like this
if (app.settings.env === 'production') {
app.error(function(err, req, res) {
res.render('500.jade', {
status: 500,
locals: {
error: error
}
});
});
}
And then set the custom message in the jade file like:
h2 Error
p Something went wrong with the application.
h3 Error Details
pre #{error}
Hope this helps
I am using node-mongodb-native driver. I tried
collection.findOne({email: 'a#mail.com'}, function(err, result) {
if (!result) throw new Error('Record not found!');
});
But the error is caught by mongodb driver and the express server is terminated.
What's the correct way for this case?
=== Edit===
I have the code below in app.js
app.configure('development', function() {
app.use(express.errorHandler({dumpExceptions: true, showStack: true}));
});
app.configure('production', function() {
app.use(express.errorHandler());
});
Related code in node_modules/mongodb/lib/mongodb/connection/server.js
connectionPool.on("message", function(message) {
try {
......
} catch (err) {
// Throw error in next tick
process.nextTick(function() {
throw err; // <-- here throws an uncaught error
})
}
});
The correct use is not to throw an error, but to pass it to next function. First you define the error handler:
app.error(function (err, req, res, next) {
res.render('error_page.jade');
})
(What's this talk about error being depracated? I don't know anything about that. But even if then you can just use use. The mechanism is still the same.).
Now in your route you pass the error to the handler like this:
function handler(req, res, next) {
collection.findOne({email: 'a#mail.com'}, function(err, result) {
if (!result) {
var myerr = new Error('Record not found!');
return next(myerr); // <---- pass it, not throw it
}
res.render('results.jade', { results: result });
});
};
Make sure that no other code (related to the response) is fired after next(myerr); (that's why I used return there).
Side note: Errors thrown in asynchronous operations are not handled well by Express (well, actually they somewhat are, but that's not what you need). This may crash your app. The only way to capture them is by using
process.on('uncaughtException', function(err) {
// handle it here, log or something
});
but this is a global exception handler, i.e. you cannot use it to send the response to the user.
I'm guessing that the error is not caught. Are you using an Express error handler? Something like:
app.error(function (err, req, res, next) {
res.render('error-page', {
status: 404
});
More on error handling in Express: http://expressjs.com/guide.html#error-handling
In terms of checking for errors off mongodb, use '!error' for success as opposed to '!result' for errors.
collection.findOne({email: 'a#mail.com'}, function(err, result) {
if (!error) {
// do good stuff;
} else {
throw new Error('Record not found!');
}
});
As for the custom 404, I've yet to do that in node and express, but I would imagine it would involve "app.router".
I have a working node.js / express based server and am using jade for templating. Usually there is no problem but a couple of times every day I get an error message when requsting any page. The error is 'failed to locate view'. I don't know why i get this error since it worked fine just minutes before.
The question however is how I can force a crash on this event, for example:
res.render('index.jade', {info: 'msg'}, function(error, ok) {
if (error)
throw new Error('');
// Proceed with response
};
How would I do this? And how would I proceed with the response?
thank you.
You can add an error handling middleware.
app.use(function handleJadeErrors(err, req, res, next) {
// identify the errors you care about
if (err.message === 'failed to locate view') {
// do something sensible, such as logging and then crashing
// or returning something more useful to the client
} else {
// just pass it on to other error middleware
next(err);
}
});
Try this:
app.use(function (req, res, next) {
fs.exists(__dirname + '/views/' + req.url.substring(1) + '.jade', function (exists) {
if(!exists) {
console.log(err);
return next();
}
res.render(req.url.substring(1), { title: "No Controller", user: req.session.user });
}
});