Initial 404 Error Handling Support

Fixes #356

- Adds new generic methods for handling errors to errorHandling.js
- Initialises generic methods as middleware
- Created error.hbs view in admin
- Error handler searches for error.hbs view file in user theme folder
  and renders it if available, otherwise lets the error fall through
  to express.

- We *could* change the final behaviour to render a default ghost
  template should the user template be missing
- Because it currently isn't possible to require(ghost) in errorHandling.js,
  it was necessary to duplicate some aspects of the ghost path init code
  inside errorhandling.js. This should be cleaned up and moved back
  into ghost.js when possible.
This commit is contained in:
Christopher Giffard 2013-09-17 20:56:05 +10:00
parent 3971abab9d
commit 48b75fa396
3 changed files with 93 additions and 9 deletions

View File

@ -277,12 +277,19 @@ when.all([ghost.init(), helpers.loadCoreHelpers(ghost)]).then(function () {
server.use(server.router);
// ### Error handling
// TODO: replace with proper 400 and 500 error pages
// 404's
server.use(function error404Handler(req, res, next) {
console.log('test', req.url);
next();
//res.send(404, {message: "Page not found"});
// 404 Handler
server.use(errors.render404Page);
// TODO: Handle all application errors (~500)
// Just stubbed at this stage!
server.use(function error500Handler(err, req, res, next) {
if (!err || !(err instanceof Error)) {
next();
}
// For the time being, just log and continue.
errors.logError(err, "Middleware", "Ghost caught a processing error in the middleware layer.");
next(err);
});
// All other errors

View File

@ -1,6 +1,14 @@
var _ = require('underscore'),
colors = require("colors"),
errors;
fs = require('fs'),
path = require('path'),
errors,
// Paths for views
appRoot = path.resolve(__dirname, '../'),
themePath = path.resolve(appRoot + '/content/themes'),
userErrorTemplatePath = path.resolve(themePath + '/error.hbs'),
userErrorTemplateExists;
/**
* Basic error handling helpers
@ -21,7 +29,7 @@ errors = {
logError: function (err, context, help) {
err = err.message || err || "Unknown";
// TODO: Logging framework hookup
// Eventually we'll have better logging which will know about envs
// Eventually we'll have better logging which will know about envs
if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'staging'
|| process.env.NODE_ENV === 'production') {
@ -61,10 +69,69 @@ errors = {
res.redirect(redirectTo);
}
};
},
renderErrorPage: function (code, err, req, res, next) {
// Render the error!
function renderErrorInt() {
// TODO: Attach node-polyglot
res.render('error', {
message: err.message || err,
code: code
});
}
if (code >= 500) {
this.logError(err, "ErrorPage");
}
// Are we admin? If so, don't worry about the user template
if (res.isAdmin) {
return renderErrorInt();
}
if (userErrorTemplateExists === false) {
return next();
}
if (userErrorTemplateExists === true) {
return renderErrorInt();
}
// userErrorTemplateExists is undefined, which means we
// haven't yet checked for it. Do so now!
fs.stat(userErrorTemplatePath, function (err, stat) {
userErrorTemplateExists = !err;
if (userErrorTemplateExists) {
return renderErrorInt();
}
// Message only displays the first time an error is triggered.
errors.logError(
"Theme error template not found",
null,
"Add an error.hbs template to the theme for customised errors."
);
next();
});
},
render404Page: function (req, res, next) {
var message = res.isAdmin ? "No Ghost Found" : "Resource Not Found";
this.renderErrorPage(404, message, req, res, next);
}
};
// Ensure our 'this' context in the functions
_.bindAll(errors, "throwError", "logError", "logAndThrowError", "logErrorWithRedirect");
_.bindAll(
errors,
"throwError",
"logError",
"logAndThrowError",
"logErrorWithRedirect",
"renderErrorPage",
"render404Page"
);
module.exports = errors;

View File

@ -0,0 +1,10 @@
{{!< default}}
<section class="error-content error-404 js-error-container">
<figure class="error-image">
<img class="error-ghost" src="/ghost/img/404-ghost@2x.png" srcset="/ghost/img/404-ghost.png 1x, /ghost/img/404-ghost@2x.png 2x"/>
</figure>
<section class="error-message">
<h1 class="error-code">{{code}}</h1>
<h2 class="error-description">{{message}}</h2>
</section>
</section>