发送后不能设置标头:多个中间件执行可靠性

时间:2017-10-31 13:47:00

标签: node.js express middleware

在我的主要express.js配置文件中,我use两个自定义错误中间件函数:

const error = require('../middlewares/error');

// catch 404 and forward to error handler
app.use(error.notFound);

// if error is not an instanceOf APIError, convert it.
app.use(error.converter);

我使用xtento documentation来统一错误消息。这是我的错误中间件:

module.exports = {
  /**
   * Error responder. Send stacktrace only during development
   * @public
   */
  responder: (err, req, res, next) => {
    res.status(err.output.payload.statusCode);
    res.json(err.output.payload);
    res.end();
  },

  /**
   * If error is not a Boom error, convert it.
   * @public
   */
  converter: (err, req, res, next) => {
    if (env !== 'development') {
      delete err.stack;
    }
    if (err.isBoom) {
      return module.exports.responder(err, req, res);
    }
    if (err.name === 'MongoError' && err.code === 11000) {
      const boomedError = boom.conflict('This email already exists');
      boomedError.output.payload.stack = err ? err.stack : undefined;
      return module.exports.responder(boomedError, req, res);
    }
    const boomedError = boom.boomify(err, { statusCode: 422 });
    return module.exports.responder(boomedError, req, res);
  },

  /**
   * Catch 404 and forward to error responder
   * @public
   */
  notFound: (req, res) => {
    const err = boom.notFound('Not Found');
    return module.exports.responder(err, req, res);
  },
};

我的问题是,当我做一个"注册"对现有电子邮件执行操作,responder()执行三次。一个用于我的boom.conflict错误,但是还有一个用于"未找到"。 (即使我已完成res.end()

这是寄存器逻辑:

exports.register = async (req, res, next) => {
  try {
    validationResult(req).throw();
    const user = new User(req.body);
    const token = generateTokenResponse(user, user.token());
    const userTransformed = user.transform();
    user.tokens.push({ kind: 'jwt', token });
    user.activationId = uuidv1();
    await user.save();
    res.status(httpStatus.CREATED);
    sendValidationEmail(user.activationId);
    return res.json({ user: userTransformed });
  } catch (err) {
    return next(converter(err, req, res, next));
  }
};

user.save()顺便触发了这个:

userSchema.pre('save', async function save(next) {
  try {
    if (!this.isModified('password')) return next();

    const rounds = env === 'test' ? 1 : 10;

    const hash = await bcrypt.hash(this.password, rounds);
    this.password = hash;

    return next();
  } catch (err) {
    return next(converter(err));
  }
});

1 个答案:

答案 0 :(得分:0)

调用res.end()只会告诉您已完成发送数据的响应流。在这种情况下,您不需要这样做,因为调用res.json()会为您完成。

但是,这与告诉Express您完成处理请求的方式并不相同。仅仅因为你发送了回复并不一定意味着你没有工作要做。

您告诉Express您已完成的方式是不致电next()。 Express假定您已默认完成,并且只有在您致电next()时才会继续执行中间件/路由链。

所以这一行:

return next(converter(err, req, res, next));

应该是:

converter(err, req, res, next);

同样,您对converter()的其他来电也不应该拨打next()