在我的主要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));
}
});
答案 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()
。