对于某些页面,我在我的应用中自定义了500,404和403错误处理。因此,例如在数据库查询失败后,我会去:
return next({status: 404, message: 'Record not found'});
或
return next(new Error('Bad things have happened')});
在我的中间件中,我有一个错误处理程序:
app.use(function (err, req, res, next) {
// handle error
});
问题是永远不会调用错误处理程序,而是将错误调用堆栈打印到浏览器中。我希望处理程序呈现自定义错误页面。
app.js
var express = require('express')
, app = express()
, swig = require('swig')
, config = require('./lib/config')
, env = process.env.NODE_ENV || 'development'
, path = require('path');
config.configure(env);
app.engine('html', swig.renderFile);
app.set('view cache', false);
swig.setDefaults({
cache: config.get('swigCache')
});
app.set('view engine', 'html');
app.set('views', __dirname + '/lib/views');
require('./lib/util/swig');
require('./lib/initialisers/mongodb')();
require('./lib/initialisers/aws')();
require('./lib/middleware')(app); // first load middleware
require('./lib/routes')(app); // then routes
var server = app.listen(config.get('port'), function() {
console.info('config: ' + JSON.stringify(config.getCurrent()));
console.info('NODE_ENV: ' + env);
console.info('server running: ' + JSON.stringify(server.address()));
});
routes.js
module.exports = function(app){
app.get('/', require('./views/').index);
app.get('/blog', require('./views/blog').index);
app.get('/blog/:slug', require('./views/blog').getBySlug);
app.route('/report/:slug')
.get(require('./views/report/').index)
.post(require('./views/report/').doReport);
// Very long file with tons of routes. Simplified version.
middleware.js
var express = require('express')
, app = express()
, path = require('path')
, logger = require('morgan')
, cookieParser = require('cookie-parser')
, bodyParser = require('body-parser')
, passport = require('passport')
, session = require('express-session')
, mongoStore = require('connect-mongo')(session)
, compression = require('compression')
, favicon = require('serve-favicon')
, config = require('./config')
, flash = require('connect-flash')
, multer = require('multer')
, csrf = require('csurf');
module.exports = function(app) {
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json());
app.use(cookieParser());
app.use(csrf({ cookie: true }));
app.use(express.static(path.join(__dirname, config.get('staticContentPath')), {
maxAge: (60 * 60 * 24) * 1000
}));
app.use(session({
resave: true,
saveUninitialized: true,
secret: 'da755fc0-6882-11e4-9803-0800200c9a66',
cookie: {
maxAge: 24 * 60 * 60 * 1000 // 24 hrs
},
store: new mongoStore({
url: config.getMongoConn()
})
}));
app.use(logger('dev'));
app.use(flash());
/**
* 301 redirects
*/
app.use(function(req, res, next) {
var host = req.get('host');
// AWS IP --> http
if (host == 'xx.xxx.xxx.xxx') {
return res.redirect(301, config.get('url') + req.originalUrl);
}
// AWS origin --> http
if(host == 'xxx-xxx-xxx-xxx-xxx.ap-southeast-2.compute.amazonaws.com'){
return res.redirect(301, config.get('url') + req.originalUrl);
}
// www --> http
if (/^www\./.test(host)) {
host = host.substring(4, host.length);
return res.redirect(301, req.protocol + '://' + host + req.originalUrl);
}
// Trailing slash --> http
if (req.path.substr(-1) == '/' && req.path.length > 1) {
var query = req.url.slice(req.path.length);
return res.redirect(301, req.path.slice(0, -1) + query);
}
next();
});
// Delete expired Mongo sessions from DB
app.use(function (req, res, next) {
req.session._garbage = new Date();
req.session.touch();
next();
});
/**
* Setting Cache control header for Ajax requests to 30 minutes
*/
app.use(function (req, res, next) {
if(req.xhr){
res.header('Cache-Control', 'max-age=' + 1800 + ', public');
}
next();
});
app.use(compression());
app.use(
multer({
dest: config.get('uploads').folders.temp
})
);
app.use(passport.initialize());
app.use(passport.session());
var initPassport = require('./passport/init');
initPassport(passport);
app.use(function (req, res, next) {
res.locals = {
root : 'http://' + req.headers.host,
sitename : require('./config').get('sitename'),
config: config.get('env'),
url : config.get('url'),
user : req.user,
flash : req.flash()
};
next();
});
app.use(function (err, req, res, next) {
if (err.code !== 'EBADCSRFTOKEN'){
return next(err);
}
if(req.xhr){
return res.ok({payload: null}, '403 invalid csrf token');
}
// TODO handle CSRF token errors here
res.status(403);
res.send('form tampered with')
});
// This is never called when throwing errors like
// next(new Error('some error') or
// next({status: 500, message:'server error'});
app.use(function (err, req, res, next) {
console.error(err.stack);
// render an error page
});
};
答案 0 :(得分:15)
注意:您的错误处理程序中间件必须具有4个参数:error,req,res,next。否则,您的处理程序将不会解雇。
答案 1 :(得分:3)
您的错误处理程序应始终位于应用程序堆栈的末端。
显然,这意味着在所有app.use()
和所有app.get()
调用之后,不仅是不是。
答案 2 :(得分:0)
我遇到了同样的问题,整天都在对问题进行故障排除。最后,找到一个简单的修复方法。这非常适合我。您需要将客户错误处理程序放在服务器实例文件(App.js / server.js)上的侦听器处理程序之前,如下所示。 祝你好运:)
app.use((error, req, res, next) => {
if (res.headersSent) {
return next(err)
}
res.status(500).send('INTERNAL SERVER ERROR !')
});
app.listen(3000, function() {
console.log('Node app is running on port 3000');
});
module.exports = app;