【问题标题】:Error-handling middleware doesn't always work错误处理中间件并不总是有效
【发布时间】:2016-05-08 21:40:20
【问题描述】:

我正在使用 Express 构建一个示例网站,但遇到了一些我不太理解的问题。
如果我理解正确,错误处理中间件应该是管道中的最后一个。例如,工作得很好:

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,如果这有什么不同的话

【问题讨论】:

  • 请评论否决票
  • 我不确定是否有否决票,但阻止我花时间回答的是无关紧要的额外代码。获得答案的最佳方式是发布您能想到的最简单的用例,而不是发布您的整个应用程序。没有人真正喜欢调试,更不用说调试别人的代码了。您不需要控制台记录端口、设置环境配置、数学来计算一天的长度等。var app = express();app.use(something); app.get("/hello",...); /*your attempt at error handling*/
  • @cdbajorin 点。我会更新帖子
  • @chester89 createServer 前段时间已弃用。有关基本示例,请参阅 Express 文档 (expressjs.com/en/starter/hello-world.html)
  • @chester89 值得注意的是,在 Express 4 中,两种情况下都没有处理错误

标签: node.js express error-handling


【解决方案1】:

当您定义路由/中间件时,您指定的path 用于查看它是否与传入请求匹配。您的请求将始终路由到第一个匹配项。一个请求可能有多个匹配项,因此这里的顺序很重要。您可以通过调用next() 函数来点击下一个匹配的路由/中间件。

当您使用app.use 挂载中间件而不指定路径时,每个路径都有资格访问该中间件。因此,如果它是您挂载的第一件事,那么每个请求都将使用该中间件。

如果你想要一个捕获所有错误处理程序,你会想要相反的——你应该在你的路由定义的最后安装中间件。您需要在处理程序中调用 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!');
})

请注意,如果当前路径不存在路由,您还将点击此 catch all 中间件。

【讨论】:

  • 另外,我怀疑您的答案同时适用于版本 3 和 4?只是好奇
【解决方案2】:

文档

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

您最后定义错误处理中间件,在其他 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
});

内部

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

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

那么,你的代码抛出错误,它会用err 调用next。基本上,它与调用next(new Error()) 相同。之后,表示尝试在中间件管道中查找具有 4 个参数的下一个中间件。在您的情况下,错误处理程序在您的阴暗控制器之前声明,因此他没有参与。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-21
    • 2021-04-14
    • 2011-05-17
    • 1970-01-01
    • 2012-12-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多