我的Express应用程序中有许多端点,它们具有许多条件。我想找到最适合他们的设计模式,而无需重复太多自己。
这是我最简单的路线之一:
router.post('/reset/:token',
asyncMiddleware(async(req, res, next) => { await reset(req, res, next, pino); })
);
在reset()
内部,我需要检查几件事,例如:
我想检查那些没有强大功能的情况,但是我不知道什么是最好的方法。
export async function reset(req, res, next) {
const email = req.body.email;
if (!email) return res.status(400).json(Error.paramsMissing('email'));
const user = await userAssociatedWithEmail(req.body.email);
if (!user) {
return res.status(501).json(Error.noActiveUserAssociatedWithEmail);
}
// Generate token
const token = await jwt.sign({ email: user.email, id: user.id }, 'shhhhh');
const emailSent = await sendForgotEmail(token, user);
if (!emailSent) return res.status(500).json(Error.emailNotSent);
else return res.json({ status: 'success', message: 'Email sent successfully.' });
}
我想要的最终结果
export async function reset(req, res, next) {
const email = req.body.email;
if (!email) return res.status(400).json(Error.paramsMissing('email'));
// If error inside userAssociatedWithEmail, I'd like to stop execution and
// return res.status(501).json(Error.noActiveUserAssociatedWithEmail) from inside
// that function, without having to add an if condition below as exists in the
// original code above
const user = await userAssociatedWithEmail(req.body.email);
const token = await jwt.sign({ email: user.email, id: user.id }, 'shhhhh');
// Again I'd like to return res.status(500).json(Error.emailNotSent)
// from inside sendForgotEmail IF there is an error
const emailSent = await sendForgotEmail(token, user);
// If everything is successful, finally I'd return this
return res.json({ status: 'success', message: 'Email sent successfully.' });
}
用字解释结果:
如果可能的话,我希望能够处理条件和情况而不必在主reset
函数中进行处理(又名,而不必将响应存储在变量中,检查变量并如果发生错误,请在主功能中输入return
。
例如,代替:
const allParamsAreValid = validParams(token, email, new_password, res);
if (!allParamsAreValid) return;
我想做类似的事情:
validateParams(token, email, new_password, res);
然后在validateParams()
内,如果缺少参数,除了用res.json({})
设置响应之外,我将强制退出程序。
有可能吗?
答案 0 :(得分:1)
您可以使所有返回承诺的异步函数以您要发送的状态和值拒绝承诺。然后,您可以在一个地方处理被拒绝的承诺:
export async function reset(req, res, next) {
try {
const email = req.body.email;
if (!email) return res.status(400).json(Error.paramsMissing('email'));
// If error inside userAssociatedWithEmail, I'd like to stop execution and
// return res.status(501).json(Error.noActiveUserAssociatedWithEmail) from inside
// that function, without having to add an if condition below as exists in the
// original code above
const user = await userAssociatedWithEmail(req.body.email);
const token = await jwt.sign({ email: user.email, id: user.id }, 'shhhhh');
// Again I'd like to return res.status(500).json(Error.emailNotSent)
// from inside sendForgotEmail IF there is an error
const emailSent = await sendForgotEmail(token, user);
// If everything is successful, finally I'd return this
res.json({ status: 'success', message: 'Email sent successfully.' });
} catch(e) {
res.status(e.status || 500).json(e.errData)
}
}
然后,如果所有异步函数都具有错误条件,它们将被拒绝,并根据被拒绝的原因设置e.status
和e.errData
。这将使您拥有一个常见的错误处理程序,并让async
函数为您将所有被拒绝的承诺收集到您的try / catch中。这是您在希望整个函数完成的一系列await
调用中处理拒绝的一种干净方法。
然后,您还需要确保asyncMiddleware()
函数也没有发送响应(无法真正告知其目的是什么)。您没有显示该代码,所以我看不到它在做什么。
您没有显示任何使用validateParams()
的代码,但是如果它是同步的,则它可能会抛出一个异常,并在其上设置了正确的字段,而try/catch
也会捕获它就像它会捕获异步拒绝一样。
例如:
function validateParams(token, email, new_password) {
let err = new Error();
err.errData = {status: 'error'};
if (!token) {
err.errData.message = 'invalid token';
throw err;
}
if (!email) {
err.errData = Error.paramsMissing('email');
throw err;
}
if (!new_password) {
err.errData.message = 'invalid new password');
throw err;
}
}
如果您愿意,也可以在validateParams()
中发送错误响应,但我认为这样做不干净,因为它们可以一次尝试收集所有错误,包括所有await
异步调用抓住了路由处理程序,坦率地说,要在某些函数调用中而不在其他函数调用中发送响应,这是更具可读性和可理解性的代码。我尝试将所有错误和成功回复都保持在同一级别。然后,很容易跟踪并避免意外发送多个响应。
然后,在您的路由处理程序中,您只需像这样调用validateParams(...)
。如果抛出该异常,则您的try / catch将捕获该异常并发送相应的错误。如果没有错误,则执行将继续。
答案 1 :(得分:0)
由于您将 res 对象传递给 validateParams 方法,因此您可以执行以下操作,
async function validateParams(token, email, new_password, res) {
if (token && emal && new_password && res) {
// all values are available
// perform your desired operation
} else {
// exit from the method and pass info to the client
return res.json({ message: 'Invalid parameter' });
}
}
在这种情况下,您要做的就是调用validateParams。
await validateParams(token, email, new_password, res);
如果缺少参数,服务器将立即将控件传递给客户端。否则,您可以在那里进行操作。