error handling中间件并不总是工作

我正在使用Express构build一个示例网站,我碰到一些我不太明白的东西。
如果我理解正确,error handling中间件应该是pipe道中的最后一个。 例如,工作得很好:

var http = require('http'); var express = require('express'); var app = express(); app.set('view engine', 'jade'); app.set('views', './views'); app.use(express.static('./public')); http.createServer(app).listen(portNumber, function() { }); app.get('/hello', function(req, res) { res.send('Welcome!'); }); app.use(function(err, req, res, next) { res.status(500).send('something broke!'); }); app.get('/error', function(req, res, next) { somethingNonExistent(2016); }); 

但是,如果我在http.createServer调用之前注册了中间件,但在所有其他中间件注册之后,它将不起作用 – 我的代码不会被调用:

 var http = require('http'); var express = require('express'); var app = express(); app.use(express.static('./public')); app.use(function(err, req, res, next) { res.status(500).send('something broke!'); }); http.createServer(app).listen(portNumber, function() { }); app.get('/hello', function(req, res) { res.send('Welcome!'); }); app.get('/error', function(req, res, next) { somethingNonExistent(2016); }); 

我在这里错过了什么? 我的猜测是,app.get调用内部使用一些中间件,它会变得混乱。
我使用Express 3.2.6和Node.js 0.10.29,如果这有什么区别的话

在定义路由/中间件时,将使用您指定的path来查看它是否与传入的请求相匹配。 您的请求将始终被路由到第一场比赛。 一个请求可能有多个匹配,所以顺序很重要。 您可以通过调用next()函数来匹配下一个匹配的路由/中间件。

当使用app.use装载中间件而不指定path时,每个path都有资格打中间件。 所以,如果这是您首先安装的,那么每个请求都将使用该中间件。

如果你想捕获所有的error handling程序,你会想要相反的 – 你应该在你的路由定义的最后安装中间件。 您需要调用处理程序中的next函数来实际访问这个中间件:

 app.get('/hello', function(req, res, next) { ... // Let's pretend that there was some error next() }); // After all of your route definitions... app.use(function(req, res) { res.status(500).send('something broke!'); }) 

请注意,如果当前path不存在路由,那么您也将碰到所有中间件。

文件

http://expressjs.com/en/guide/error-handling.html

你最后定义error handling中间件,在其他app.use()和路由调用之后; 例如:

 var bodyParser = require('body-parser'); var methodOverride = require('method-override'); app.use(bodyParser()); app.use(methodOverride()); app.use(function(err, req, res, next) { // logic }); 

内置的

为了便于理解,你可以想象pipe道。 当你的控制器收到一个请求,在Express中,看起来像这样

 try { fn(req, res, next); // your controller } catch (err) { next(err); } 

那么,那么你的代码就会抛出错误, next就会调用err 。 基本上和next(new Error())调用一样next(new Error()) 。 之后,表示试着在中间件pipe道中find具有4个参数的下一个中间件。 在你的情况下, 你的黑幕控制器之前声明的error handling程序,所以他不参与。

从技术上讲,控制器和中间件没有区别。 或者,您可以传入控制器的next参数,并调用它以进一步通过pipe道。 如果你没有调用next() ,你完成处理请求。