2015-04-17 19 views
17

Bazı sayfalar için uygulamanızda özel 500, 404 ve 403 hata işleme var. Yani başarısız bir veritabanı sorgusu sonra mesela ben de giderdim:Express 4 middleware hata işleyicisi çağrılmadı

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

veya

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

benim katman ben bir hata işleyicisi var:

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

Sorun olduğunu hata işleyicisi asla çağrılmaz, bunun yerine tarayıcıya hata çağrıları yazdırılır. İşleyicinin özel bir hata sayfası oluşturmasını istiyorum.

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

"app.use (işlev (err, req, res, next) {" öğesinin iki kez bildirimi var. Res.status (403) döndürülüyor mu? –

+0

Ancak bu, bir sonraki (hata) olmadığı sürece bozuk CSRF belirteç hatası Kodun bu bloğunu çıkarsam ve sadece tek bir app.use (işlev (err, req, res, sonraki)) almamam bile, asla çağrılmaz. – ChrisRich

+9

Yollar, her şey aynı şekilde kullanıldığından, ara katman yazılımı olarak sınıflandırılır Hata işleyicileri her zaman çağrı yığınının sonunda olmalı, kendi dosyalarına ekleyin ve rotalarınızdan sonra ekleyin. [Dokümanları işlerken hata] (http://expressjs.com/guide/error-handling.html) Eğer middleware hata işleyicinizi korumak istiyorsanız, o zaman rotalarınızdan sonra eklemelisiniz .. –

cevap

24

sorun hata işleyicileri hep sonunda olmalıdır yani, senin uygulama yığını Bu, hata işleyicisini middleware'inizden app.js'ye taşıyabildiğiniz ve bunları (app.use()) ya da ara yazılımınızı ara katman yazılımınızdan önce ekleyebileceğiniz anlamına gelir.

+2

Dang! uygulamanın başlatılmasının ortasında ve rota tanımında ced. – JohnnyQ

+0

Sadece OP kapsamındaki rotaların tümünü rotaların tamamen aktarılmasıyla ilgili bir problem fark ettim. 'BodyParsers' ve 'urlEncoders' işe yaramayacak, bu iki orta sınıf arasında yollar yerleştirilmelidir. – JohnnyQ

+0

Gotcha! Bütün gün boyunca bununla mücadele etti: https://stackoverflow.com/questions/46929330/express-async-await-error-handling - sorunumun ne olduğunu ve bunun nasıl çözüldüğünü yayınlayacak. – npr

İlgili konular