I have a node.js + Express + express-handlebars app. I want to redirect the users to 404 page when they go to a page that does not exists and redirect them to a 500 when there is an internal server error or an exception(without stopping the server). In my app.js I have written the middle ware at the end to perform these tasks.
app.get('*', function(req, res, next) {
var err = new Error();
err.status = 404;
next();
});
//Handle 404
app.use(function(err, req, res, next){
res.sendStatus(404);
res.render('404');
return;
});
//Handle 500
app.use(function(err, req, res, next){
res.sendStatus(500);
res.render('500');
});
//send the user to 500 page without shutting down the server
process.on('uncaughtException', function (err) {
console.log('-------------------------- Caught exception: ' + err);
app.use(function(err, req, res, next){
res.render('500');
});
});
However only the code for 404 works. So if I try to go to an url
localhost:8000/fakepage
it successfully redirects me to my 404 page. The 505 does not work. And for the exception handling, the server does keep running but, it does not redirect me to the 500 error page after the console.log
I am confused by so many solutions online where people seem to implement different techniques for this.
Here are some of the resources I looked at
http://www.hacksparrow.com/express-js-custom-error-pages-404-and-500.html
Correct way to handle 404 and 500 errors in express
How to redirect 404 errors to a page in ExpressJS?
https://github.com/expressjs/express/blob/master/examples/error-pages/index.js
The process on uncaughtexception is for the application process - not a per request error handler. Note it takes an err in it's callback and res is not passed. It's a global application exception handler. It's good to have that in the event your global code throws.
One option is you can have all your normal routes (don't see in your example), then a non error handler final * route for 404. That's always the last route meaning it has fallen through all the other routes not finding a match ... thus not found. It's not an exception handling case - you conclusively know the path they are requesting has no match since it has fallen through.
How to redirect 404 errors to a page in ExpressJS?
Then the err route can return 500
http://expressjs.com/en/guide/error-handling.html
The problem is you have two error routes so it always hits the first one which hard codes returning a 404.
The express 4 tool creates this pattern:
var users = require('./routes/users');
// here's the normal routes. Matches in order
app.use('/', routes);
app.use('/users', users);
// catch 404 and forward to error handler
// note this is after all good routes and is not an error handler
// to get a 404, it has to fall through to this route - no error involved
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers - these take err object.
// these are per request error handlers. They have two so in dev
// you get a full stack trace. In prod, first is never setup
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
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.render('error', {
message: err.message,
error: {}
});
});
Related
I thought this was a caching issue, but after three complete removals of all code on my server, I'm still encountering the same issue:
Express Generator comes with the default error handling in the app.js file:
// 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.redirect('/');
});
I have since replaced that code with my own catch all route, using app.all:
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', index);
app.use('/users', users);
// catch 404 and forward to error handler (catch-all)
app.all('*', function(req, res) {
res.render('index.html');
});
Keep in mind that the render statement works. I'm using a single page application and I need it to redirect back to the index.html file.
This actually works locally, but does not work on my server. The server is a Node.js server.
The default message for the 404 error is "Not Found". No matter how many times I remove this code and the 404 error message, I continue to see "Not Found" (Express.js style) on my browser, instead of a redirect to my home page.
Coming back to this question, the issue was with my web host. The server uses Phusion Passenger and the app.js on the Node.js server needed to be restarted.
I needed to create a file in the root of the server called restart.txt inside of a folder named 'tmp':
nano tmp/restart.txt
Afterwards, if I wanted to manually restart the server, I would have to run the following command:
touch tmp/restart.txt
Which would restart the app.js file.
I have node 7.8.0 and I have read Node.js Best Practice Exception Handling
Still I can't seem to understand error handling in node.js.
For my http I have
server.on('error', () => console.log('Here I should be replacing
the Error console.'));
For 404 I have this code
app.use((req, res, next) => {
let err = new Error('Not Found');
err.status = 404;
next(err);
});
app.use((err, req, res) => {
res.status(err.status);
res.render('error');
});
404 is being caught, it creates the Error object and then it's handled by rendering the error view correctly as I want. But it also throws error log to my console and I have no idea where that is coming from and how to stop it.
I would like to use my own error handling and never actually write errors like 404 into the console.
Codes that I tried and don't seem to work.
var server = http.createServer(app);
const onError = () => console.log('Here I should be replacing the Error console.');
server.on('error', onError);
server.on('uncaughtException', onError);
process.on('uncaughtException', onError);
I'm not sure how it can render the error view, given that error handlers require 4 arguments while you're passing it only 3. This is how Express can distinguish error handlers from normal route handlers (documented here).
Try this instead:
app.use((err, req, res, next) => {
res.status(err.status);
res.render('error');
});
This is due to expressjs. Expressjs if the env is not equal to the test, the all errors writes to the console.
function logerror(err) {
if (this.get('env') !== 'test') console.error(err.stack || err.toString());
}
Also http.Server does not have an event named error.
I am using node express (4.15.2), with the default error handler created using express generator function to handle errors.
The code is:
const app = express();
app.set('port', config.enviroment.portNumber);
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, config.client.app)));
app.post(config.route.postUploads, uploader.onUpload);
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) {
// this function is never called
// 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');
});
const server = app.listen(app.get('port'), () => {
const port = server.address().port;
});
In my application I using the following line of code when I need to create an error:
new Error('Some custom error');
But the error handler is never called.
Notes: the error handler is placed after the latest app.use but before app.listen.
Any ideas what could cause this issue and how to fix it?
You need to place the said function at the very bottom of the code because ordering of routes matters (see thisenter link description here). Also, you need to throw your error like so throw new Error('Custom error') in order to trigger the error in your app.
I found a straightforward solution to my problem, basically I had to use
throw new Error('Some custom error');
In general express follows the way of passing errors rather than throwing it, for any errors in the program it could be a good idea to pass the error object to 'next' , and using and error handler so that all the errors passed to next can be handled properly.
The typical errors I expect to see logged are not being logged in my express routes.
for example:
router.get('/', function(req,res,next){
console.log(undefinedVariable)
})
I expect to get an error:
ReferenceError: undefinedVarialbe is not defined;
however In the router.get I don't get any errors other than:
GET / 500 3.641 ms - 478
in my console which is making debugging hard. Is there any way to get these errors to show in the console?
At the end of your routes, add this:
router.use(function (err, req, res, next) {
if (err) {
console.log('Error', err);
} else {
console.log('404')
}
});
This will catch all routes that were not handled by a handler before it, and all routes that resulted in an error.
If you used express-generator, there should already be an 'error handler' in app.js
Just add this to the bottom of that handler:
if (app.get('env') === 'development') console.log(err.stack);
If at any point, I get an error, by trying to do something with an undefined, my entire express app crashes with a TypeError, instead of handling it nicely by redirecting to an HTTP 500 page.
Is there any way to handle these exceptions generally, or I will need to manually check in my router methods?
Have you tried this from the docs - Express Error handling?
Error-handling middleware are defined just like regular middleware, however must be defined with an arity of 4, that is the signature (err, req, res, next):
app.use(function(err, req, res, next) {
console.error(err.stack);
res.send(500, 'Something broke!');
});
Though not mandatory error-handling middleware are typically defined very last...
Maybe try { ... } catch(e) {...} is what you are looking for?
Or just checks if value is not undefined. Simple if (value) { ... will do the job
As mentioned by phenomenal you can use express error handler middle-ware to handle error at centralized place.
app.use(function(err, req, res, next) {
console.error(err.stack);
res.send(500, 'Something broke!');
});
Than to pass error from your routes you can use next to pass error to this middle-ware like this
app.get('/login',function(req,res,next){
next("your error"); // The error middle-ware handle this error.
})