0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-20 22:42:53 -05:00

Moved theme-specific error handling to frontend

- our themeErrorRenderer is only used in the frontend.. move it there
- this required exposing prepareError as shared middleware
- TODO: move these shared compontents to @tryghost/error
This commit is contained in:
Hannah Wolfe 2021-11-29 15:38:07 +00:00
parent d7c4168452
commit ad9eb35746
No known key found for this signature in database
GPG key ID: AB586C3B5AE5C037
4 changed files with 99 additions and 88 deletions

View file

@ -0,0 +1,93 @@
const hbs = require('express-hbs');
const _ = require('lodash');
const tpl = require('@tryghost/tpl');
const sentry = require('../../../shared/sentry');
const config = require('../../../shared/config');
const helpers = require('../../services/routing/helpers');
// @TODO: make this properly shared code
const shared = require('../../../server/web/shared/middleware/error-handler');
const messages = {
oopsErrorTemplateHasError: 'Oops, seems there is an error in the error template.',
encounteredError: 'Encountered the error: ',
whilstTryingToRender: 'whilst trying to render an error page for the error: '
};
const escapeExpression = hbs.Utils.escapeExpression;
/**
* This is a bare minimum setup, which allows us to render the error page
* It uses the {{asset}} helper, and nothing more
*/
const createHbsEngine = () => {
const engine = hbs.create();
engine.registerHelper('asset', require('../../helpers/asset'));
return engine.express4();
};
const errorFallbackMessage = err => `<h1>${tpl(messages.oopsErrorTemplateHasError)}</h1>
<p>${tpl(messages.encounteredError)}</p>
<pre>${escapeExpression(err.message || err)}</pre>
<br ><p>${tpl(messages.whilstTryingToRender)}</p>
${err.statusCode} <pre>${escapeExpression(err.message || err)}</pre>`;
const themeErrorRenderer = (err, req, res, next) => {
// If the error code is explicitly set to STATIC_FILE_NOT_FOUND,
// Skip trying to render an HTML error, and move on to the basic error renderer
// We do this because customised 404 templates could reference the image that's missing
// A better long term solution might be to do this based on extension
if (err.code === 'STATIC_FILE_NOT_FOUND') {
return next(err);
}
// Renderer begin
// Format Data
const data = {
message: err.message,
// @deprecated Remove in Ghost 5.0
code: err.statusCode,
statusCode: err.statusCode,
errorDetails: err.errorDetails || []
};
// Template
// @TODO: very dirty !!!!!!
helpers.templates.setTemplate(req, res);
// It can be that something went wrong with the theme or otherwise loading handlebars
// This ensures that no matter what res.render will work here
// @TODO: split the error handler for assets, admin & theme to refactor this away
if (_.isEmpty(req.app.engines)) {
res._template = 'error';
req.app.engine('hbs', createHbsEngine());
req.app.set('view engine', 'hbs');
req.app.set('views', config.get('paths').defaultViews);
}
// @TODO use renderer here?!
// Render Call - featuring an error handler for what happens if rendering fails
res.render(res._template, data, (_err, html) => {
if (!_err) {
return res.send(html);
}
// re-attach new error e.g. error template has syntax error or misusage
req.err = _err;
// And then try to explain things to the user...
// Cheat and output the error using handlebars escapeExpression
return res.status(500).send(errorFallbackMessage(_err));
});
};
module.exports.handleThemeResponse = [
// Make sure the error can be served
shared.prepareError,
// Handle the error in Sentry
sentry.errorHandler,
// Render the error using theme template
themeErrorRenderer
];

View file

@ -1,4 +1,5 @@
module.exports = {
errorHandler: require('./error-handler'),
handleImageSizes: require('./handle-image-sizes'),
redirectGhostToAdmin: require('./redirect-ghost-to-admin'),
serveFavicon: require('./serve-favicon'),

View file

@ -184,7 +184,7 @@ module.exports = function setupSiteApp(options = {}) {
app.setupErrorHandling(siteApp);
}
});
siteApp.use(shared.middleware.errorHandler.handleThemeResponse);
siteApp.use(mw.errorHandler.handleThemeResponse);
debug('Site setup end');

View file

@ -1,16 +1,10 @@
const hbs = require('express-hbs');
const _ = require('lodash');
const debug = require('@tryghost/debug')('error-handler');
const errors = require('@tryghost/errors');
const tpl = require('@tryghost/tpl');
const config = require('../../../../shared/config');
const helpers = require('../../../../frontend/services/routing/helpers');
const sentry = require('../../../../shared/sentry');
const messages = {
oopsErrorTemplateHasError: 'Oops, seems there is an error in the error template.',
encounteredError: 'Encountered the error: ',
whilstTryingToRender: 'whilst trying to render an error page for the error: ',
pageNotFound: 'Page not found',
resourceNotFound: 'Resource not found',
actions: {
@ -45,19 +39,6 @@ const messages = {
}
};
const escapeExpression = hbs.Utils.escapeExpression;
/**
* This is a bare minimum setup, which allows us to render the error page
* It uses the {{asset}} helper, and nothing more
*/
const createHbsEngine = () => {
const engine = hbs.create();
engine.registerHelper('asset', require('../../../../frontend/helpers/asset'));
return engine.express4();
};
const updateStack = (err) => {
let stackbits = err.stack.split(/\n/g);
@ -87,7 +68,7 @@ const updateStack = (err) => {
/**
* Get an error ready to be shown the the user
*/
const prepareError = (err, req, res, next) => {
module.exports.prepareError = (err, req, res, next) => {
debug(err);
if (Array.isArray(err)) {
@ -201,61 +182,6 @@ const prepareUserMessage = (err, res) => {
return userError;
};
const errorFallbackMessage = err => `<h1>${tpl(messages.oopsErrorTemplateHasError)}</h1>
<p>${tpl(messages.encounteredError)}</p>
<pre>${escapeExpression(err.message || err)}</pre>
<br ><p>${tpl(messages.whilstTryingToRender)}</p>
${err.statusCode} <pre>${escapeExpression(err.message || err)}</pre>`;
const themeErrorRenderer = (err, req, res, next) => {
// If the error code is explicitly set to STATIC_FILE_NOT_FOUND,
// Skip trying to render an HTML error, and move on to the basic error renderer
// We do this because customised 404 templates could reference the image that's missing
// A better long term solution might be to do this based on extension
if (err.code === 'STATIC_FILE_NOT_FOUND') {
return next(err);
}
// Renderer begin
// Format Data
const data = {
message: err.message,
// @deprecated Remove in Ghost 5.0
code: err.statusCode,
statusCode: err.statusCode,
errorDetails: err.errorDetails || []
};
// Template
// @TODO: very dirty !!!!!!
helpers.templates.setTemplate(req, res);
// It can be that something went wrong with the theme or otherwise loading handlebars
// This ensures that no matter what res.render will work here
// @TODO: split the error handler for assets, admin & theme to refactor this away
if (_.isEmpty(req.app.engines)) {
res._template = 'error';
req.app.engine('hbs', createHbsEngine());
req.app.set('view engine', 'hbs');
req.app.set('views', config.get('paths').defaultViews);
}
// @TODO use renderer here?!
// Render Call - featuring an error handler for what happens if rendering fails
res.render(res._template, data, (_err, html) => {
if (!_err) {
return res.send(html);
}
// re-attach new error e.g. error template has syntax error or misusage
req.err = _err;
// And then try to explain things to the user...
// Cheat and output the error using handlebars escapeExpression
return res.status(500).send(errorFallbackMessage(_err));
});
};
module.exports.resourceNotFound = (req, res, next) => {
next(new errors.NotFoundError({message: tpl(messages.resourceNotFound)}));
};
@ -266,7 +192,7 @@ module.exports.pageNotFound = (req, res, next) => {
module.exports.handleJSONResponse = [
// Make sure the error can be served
prepareError,
module.exports.prepareError,
// Handle the error in Sentry
sentry.errorHandler,
// Render the error using JSON format
@ -275,7 +201,7 @@ module.exports.handleJSONResponse = [
module.exports.handleJSONResponseV2 = [
// Make sure the error can be served
prepareError,
module.exports.prepareError,
// Handle the error in Sentry
sentry.errorHandler,
// Render the error using JSON format
@ -284,16 +210,7 @@ module.exports.handleJSONResponseV2 = [
module.exports.handleHTMLResponse = [
// Make sure the error can be served
prepareError,
module.exports.prepareError,
// Handle the error in Sentry
sentry.errorHandler
];
module.exports.handleThemeResponse = [
// Make sure the error can be served
prepareError,
// Handle the error in Sentry
sentry.errorHandler,
// Render the error using theme template
themeErrorRenderer
];