明确表示下一个(错误)是否必须具有特定格式?

时间:2018-06-14 09:05:37

标签: javascript node.js express swagger

我有一个使用http-errors模块的快速子应用程序。当我将new Forbidden()传递给next()回调时,它会消失在以太网中并且不会回调。如果我通过new Error(){ message: 'Forbidden' },则会触发子应用错误处理程序。这是预期的行为吗?

我已创建自己的错误对象,但它们都有效。我看到http-errors使用的inherits模块适用于我。错误处理程序是否检查错误参数上的任何内容?

我已经使用http-errors多年了,之前没有注意到这个问题。

const { Forbidden } = require('http-errors')
const express = require('express')

const app = express()

const subapp = express()

subapp.get((req, res, next) => {
  next(new Forbidden()) // doesn't work
  next(new Error()) // works
  next({ message: 'Forbidden' }) // works
})
subapp.use((err, req, res, next) => {
  // only called if new Error() or { message: 'Forbidden' }
})

app.use('/somepath', subapp)

app.use((err, req, res, next) => {
  // not called
})

编辑:

我忽略了我在上面的问题中使用了招摇。 Swagger正在捕捉错误但没有正确处理它;它设置了正确的标题但没有发送完整的响应。因此它错过了我的错误中间件并传递给下一个非错误的中间件。

// return response for http-errors error
subapp.use((req, res, next) => {
  if (res.headersSent) {
    return res.end()
  }
  next()
})

1 个答案:

答案 0 :(得分:1)

回答直接问题,不是没有。我们可以使用此代码中显示的更简单的案例(已测试)来测试它。

const app = require('express')();

app.get('/test', (req, res, next) => {
    const nonErrObj = {
        hello: 'world'
    };

    return next(nonErrObj);
});

app.use((err, req, res, next) => {
    console.log('Got an error');
    console.table(err);

    res.sendStatus(500);
});

app.listen(3000, () => {
    console.log('listening on 3000');
});

然后在另一个终端运行curl localhost:3000/test,我们得到输出:

listening on 3000
Got an error
┌─────────┬─────────┐
│ (index) │ Values  │
├─────────┼─────────┤
│  hello  │ 'world' │
└─────────┴─────────┘

这个console.table由我们的错误处理程序输出,我们传递给next的对象只是一个标准的JS对象。所以传递给“next”的对象可以是任何东西,它将触发错误处理代码。

现在让我们尝试解决您的问题。我有一个预感,它与你的嵌套应用程序有关,它很好地利用了express,但有时会让人感到有些困惑。我使用您的代码创建了另一个测试应用程序,显示以下内容。此代码只有一个全局错误处理程序。

const express = require('express');
const app = express();
const subapp = express();

// Create a top level route to test
app.get('/test', (req, res, next) => {
    const nonErrObj = {
        hello: 'world'
    };

    return next(nonErrObj);
});

// Create a sub express app to test
subapp.use('/test2', (req, res, next) => {
    const nonErrObj = {
        hello: 'world'
    };

    return next(nonErrObj);
});

// Mount the app, so we can now hit /subapp/test2
app.use('/subapp', subapp);

// A single global error handler for now
app.use((err, req, res, next) => {
    console.log('Got an error');
    console.table(err);

    res.sendStatus(500);
});

app.listen(3000, () => {
    console.log('listening on 3000');
});

如果我们现在curl localhost:3000/subapp/test2curl localhost:3000/test我们得到相同的回复。我们的全局错误处理程序被调用没有问题。现在让我们尝试向子应用程序添加一个错误处理程序,看看会发生什么。

在这种情况下,我刚刚在/test2路线下添加了以下内容(为简洁起见,未添加完整文件。

subapp.use((err, req, res, next) => {
    console.log('Sub app got error');
    console.table(err);

    res.sendStatus(500);
});

在这种情况下,通过执行相同的操作,我们可以看到对localhost:3000/subapp/test2的请求仅调用子应用程序错误处理程序。这表明错误正在妥善处理。

从上面我们可以看出,通过传递随机JS对象没有任何问题(您可以深入了解Express Router代码并查看此内容)。我可以看到http-errors无法正常工作的唯一原因是它们是否会导致与错误处理代码发生冲突。

查看express router code我们可以看到它正在从错误对象中获取一些属性并根据该属性进行操作。我会检查您的http-errors禁止错误对象是否与这些用例中的一个意外冲突。如果是这种情况,那么我建议找一个不同的错误库。

我假设你也在使用npm http-errors库。如果是这种情况,看起来您应该提供有关错误创建的消息。你可能会因为你没有提供信息而陷入程序悬挂或错误的情况。