Express 4中间件error handling程序不被调用

对于某些页面我有我的应用程序中的自定义500,404和403error handling。 因此,例如在一个不成功的数据库查询后,我会去:

return next({status: 404, message: 'Record not found'}); 

要么

 return next(new Error('Bad things have happened')}); 

在我的中间件中,我有一个error handling程序:

 app.use(function (err, req, res, next) { // handle error }); 

问题是从来没有调用error handling程序,而是将错误的callstack打印到浏览器中。 我想要处理程序呈现自定义错误页面。

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 }); }; 

问题是,你的error handling程序应该总是在应用程序堆栈的最后。 这意味着您可以将error handling程序从中间件移动到您的app.js,并在需要( app.use() )之后使用它们,或者在中间件之前包含路由。