【问题标题】:nodejs middleware execution continues after returnnodejs中间件返回后继续执行
【发布时间】:2019-11-24 03:22:08
【问题描述】:

我有以下中间件:

const mongoose = require('mongoose');

module.exports = function(req, res, next) {
  const keys = Object.keys(req.params);
  keys.forEach(elem => {
    if (
      (elem.includes('id') || elem.includes('Id')) &&
      !mongoose.Types.ObjectId.isValid(req.params[elem])
    )
      return res
        .status(400)
        .json({ msg: `id: ${req.params[elem]} is invalid` });
  });
  next();
};

在获取请求中调用:

// @route   GET api/movies/:id
// @desc    Get a movie with specified id from db
// @access  Public
router.get('/:id', checkId, async (req, res) => {
const movie = await Movie.findById(req.params.id);
res.json(movie);
});

当我在邮递员中使用无效 id(例如:1234)发出请求时,我收到正确的响应为 400 并带有 msg: 'id 1234 is invalid' 但执行仍然传递到请求回调代码并引发错误当我尝试使用无效 ID 访问数据库时。

所以问题是为什么中间件仍然允许执行 next() 即使它已经返回了 400?

【问题讨论】:

  • 这能回答你的问题吗? how to stop middleware chain?
  • 您正在循环返回 http 响应!最好写一个承诺并拒绝无效,然后处理承诺。
  • 您的主要问题答案是:由于 JS 的异步特性。

标签: node.js middleware


【解决方案1】:

您需要通过调用next("some-error") 告诉路由器出现问题。例如,您可以这样做:

module.exports = function(req, res, next) {
  const keys = Object.keys(req.params);
  keys.forEach(elem => {
    if (
      (elem.includes('id') || elem.includes('Id')) &&
      !mongoose.Types.ObjectId.isValid(req.params[elem])
    ) {
      res
        .status(400)
        .json({ msg: `id: ${req.params[elem]} is invalid` });
      return next("invalidinput");
    }
  });
  next();
};

或者,如果您愿意,可以通过在路由器外部设置结果来更通用,如下所示:

在您的中间件中:

module.exports = function(req, res, next) {
  const keys = Object.keys(req.params);
  keys.forEach(elem => {
    if (
      (elem.includes('id') || elem.includes('Id')) &&
      !mongoose.Types.ObjectId.isValid(req.params[elem])
    ) {
      // === Report the error and let the router handle it
      return next({
        type: "invalidinput",
        msg: `id: ${req.params[elem]} is invalid`
      );  
    }
  });
  next();
};

然后在你的路由器底部:

// handle any errors
router.use(err, req, res, next) => {
  if (err) {
    if (err.type === "invalidinput") {
      return req.status(400).json({msg: err.msg});
    }
    else {
      return res.status(500).json({msg: "Internal error."});
    }
  }
  return next();
}

【讨论】:

    【解决方案2】:

    这里另一种可能的解决方案是将 forEach 转换为经典的 for 循环,从而使该中间件同步运行

    module.exports = function(req, res, next) {
      const keys = Object.keys(req.params);
      for (let i = 0; i < keys.length; i++) {
        if (
          (keys[i].includes('id') || keys[i].includes('Id')) &&
          !mongoose.Types.ObjectId.isValid(req.params[keys[i]])
        )
          return res
            .status(400)
            .json({ msg: `id: ${req.params[keys[i]]} is invalid` });
      }
      next();
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-07
      • 1970-01-01
      • 2020-04-14
      • 2021-08-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多