2015-04-17 12 views
17

Für bestimmte Seiten habe ich benutzerdefinierte 500, 404 und 403 Fehlerbehandlung in meiner App. So zum Beispiel nach einer erfolglosen Datenbankabfrage würde ich gehen:Express 4 Middleware Fehlerhandler nicht aufgerufen

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

oder

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

In meiner Middleware habe ich ein Fehler-Handler:

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

Problem ist, dass die Fehlerbehandlung wird nie aufgerufen, stattdessen wird der Fehler-Callstack in den Browser gedruckt. Ich möchte, dass der Handler eine benutzerdefinierte Fehlerseite ausgibt.

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

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

Sie haben "app.use (function (err, req, res, next) {" zweimal deklariert. Wird der res.status (403) zurückgegeben? –

+0

Aber das kommt als nächstes (Fehler) zurück, es sei denn es ist ein Schlechter CSRF-Token-Fehler Auch wenn ich diesen Code-Block herausnehme und nur eine einzige App habe.use (function (err, req, res, next) wird nie aufgerufen. – ChrisRich

+9

Routen werden als Middleware eingestuft, da alles dasselbe verwendet Fehlerbehebungsroutinen sollten sich immer am Ende des Aufruf-Stacks befinden. Fügen Sie sie zu ihrer eigenen Datei hinzu und fügen Sie sie nach Ihren Routen hinzu. [Error handling docs] (http://expressjs.com/guide/error-handling.html) Wenn Sie Ihren Middleware Error Handler behalten möchten, müssen Sie auch nach Ihren Routen hinzufügen. –

Antwort

24

Das Problem ist, dass Ihre Fehlerbehandlungsroutinen immer am Ende sein sollen Ihre Anwendungsstapel. Das bedeutet, dass Sie den Error-Handler entweder von Ihrer Middleware in Ihre app.js verschieben und nach Ihren Anforderungen (app.use()) oder Ihre Routen vor Ihrer Middleware einbinden können.

+2

Dang! Ich nahm Middlewares wörtlich und pla ced es in der Mitte der App-Initialisierung und der Routen-Definition. – JohnnyQ

+0

Ich habe gerade ein Problem damit festgestellt, dass ich die Routen im Rahmen des OP komplett unter die Routen übertragen habe. Die 'bodyParser' und' urlEncoder' funktionieren nicht, die Routen sollten zwischen diesen 2 Middlewares liegen. – JohnnyQ

+0

Gotcha! Der ganze Tag damit beschäftigt: https://stackoverflow.com/questions/46929330/express-async-mait-error-handling - wird posten, was mein Problem war und wie das gelöst wurde. – npr

Verwandte Themen