如何使用express.Router实例进行错误处理

Bas*_*sti 5 javascript error-handling node.js express

根据文档,任何nodejs Express中间件功能都可以替换为App或Router实例:

由于路由器和应用程序实现了中间件接口,因此您可以像使用任何其他中间件功能一样使用它们。

这是我使用的一些通用错误处理:

express()
    .use('/test', new TestRouter())
    .use((err, req, res, next) => {
        console.error(err.stack);
        res.status(500).send(err.message);
    })
    .listen(PORT);
Run Code Online (Sandbox Code Playgroud)

我尝试用错误处理路由器替换错误处理,但现在回调永远不会执行,并且 Express 使用它的默认错误处理。

const handler = new express.Router();
handler.use((err, req, res, next) => {
    console.error(err.stack);
    res.status(500).send(err.message);
});

express()
    .use('/test', new TestRouter())
    .use(handler)
    .listen(PORT);
Run Code Online (Sandbox Code Playgroud)

为什么这没有按预期工作,我该如何解决它?

Jam*_*mes 4

use根据文档,错误处理程序需要配置为最后一次调用

最后定义错误处理中间件,在其他 app.use() 和路由调用之后;

我想说“路由”也包含路由器,因此您尝试做的事情看起来不受支持。


只是进一步深入研究这一点,我相信问题归结于路由器具有单独的层堆栈这一事实。Express 在幕后实际上只是一个Router(我们在这里看到它的设置位置,然后进一步向下将中间件委托给路由器)。在内部,中间件函数表示为“层”(如此处所示,查看构造函数,我们可以看到路由器有自己的堆栈。

因此,请考虑以下示例:

express()
  .use(new RouterA())
  .use(new RouterB())
  .use((err, req, res, next) => {
    ...
  })
  .listen(PORT);
Run Code Online (Sandbox Code Playgroud)

通过查看源码,可以将其视为:

express()
  .use((req, res, next) => {
    router.handle(req, res, next);
  })
  .use((req, res, next) => {
    router.handle(req, res, next);
  })
  .use((err, req, res, next) => {
    ...
  });
Run Code Online (Sandbox Code Playgroud)

因此,如果在 中抛出错误RouterA,路由器将首先检查其自己的中间件堆栈中是否有匹配的错误层(即函数(err, req, res, next))并执行它,然后它会冒泡到应用程序级别并执行相同的操作。

因此,给出您的示例,如果您考虑翻译后的代码,这解释了为什么它不会在第二个路由器中捕获您的错误处理程序 - 路由器签名与错误处理程序的签名不匹配,因此它将被跳过。