Reputation: 640
Question: Using Express how do I redirect a client to an error page when an error is thrown inside an interior function? Logging the error from a function several layers deep is no problem, the redirection is what I don't understand.
Example that works: The following simplified code doesn't use an interior function and successfully redirects the client to an error page when an error is thrown.
app.get('/', function(req, res, next) {
let cat = 10;
try {
if (cat === 10) throw new Error('cat should not be 10');
} catch(error) {
return next(error);
}
res.render('homepage');
}
);
// custom error handler
app.use( function(error, req, res, next) {
let filePath = path.join(__dirname, '/error-pages/400.html');
res.status(400).sendFile(filePath);
});
Uh oh, this one doesn't work: Unfortunately, when an interior function is used the client always gets to res.render('homepage')
. In real code the error is almost always going to be several layers deep so there must be a logical solution to this common problem.
app.get('/', function(req, res, next) {
interiorFunction(next);
res.render('homepage');
}
);
function interiorFunction(next) {
let cat = 10;
try {
if (cat === 10) throw new Error('cat should not be 10');
} catch(error) {
return next(error);
}
}
// custom error handler
app.use( function(error, req, res, next) {
let filePath = path.join(__dirname, '/error-pages/400.html');
res.status(400).sendFile(filePath);
});
Upvotes: 1
Views: 1150
Reputation: 863
I interpret interior function as an intermediate middleware.
The way you showed it always hit the res.render('homepage')
, also you are not calling next()
when the middleware has no error, you can fix it by doing:
app.get('/', interiorFunction, function (req, res, next) {
res.render('homepage');
});
function interiorFunction(req, res, next) {
let cat = 11;
try {
if (cat === 11) throw new Error('cat should not be 10');
next();
} catch (error) {
return next(error);
}
}
EDIT
That was a solution based on middleware, but that seems that its not your case so the alternative is to have some logic to not call res.render('homepage')
when there is an error. This is common to both the approaches: they both don't run the res.render('homepage')
statement, in the end all resumes to if that code is run or not. So as an very simple working example:
app.get('/', function (req, res, next) {
const ok = interiorFunction(next);
if (ok) {
res.render('homepage');
}
});
function interiorFunction(next) {
let cat = 11;
try {
if (cat === 11) throw new Error('cat should not be 10');
return true;
} catch (error) {
next(error);
return false;
}
}
// custom error handler
app.use(function (error, req, res, next) {
let filePath = path.join(__dirname, '/error-pages/400.html');
res.status(400).sendFile(filePath);
});
EDIT 2: Or even better:
app.get('/', function (req, res, next) {
try {
interiorFunction();
res.render('homepage');
} catch (error) {
console.log(error);
next(error);
}
});
function interiorFunction() {
let cat = 11;
if (cat === 11) throw new Error('cat should not be 10');
}
So the pattern here is not to pass the next
function to interior functions, it don't make sense at all since they don't need to know that next
exist, but instead make them throw exceptions and in the top caller, use a catch
block to call next(error)
and at the same time you're not running the res.render('homepage')
line
Upvotes: 1