我正在构建一个 api 并尝试使用 req.cookie
创建一些 cookie。
最初我遇到了一个问题,因为在我的同步代码中发送响应之前,cookie 并未全部设置:
const createTokensAndCookies = catchAsync(async (req, res) => {
const promises = [];
promises.push(jwtToken.sign({ id: req.user._id }));
promises.push(jwtRefreshToken.create());
promises.push(csrfToken.create());
const tokens = await Promise.all(promises);
//create coookies
jwtCookie.create(req, res, tokens[0]);
jwtRefreshCookie.create(req, res, tokens[1]);
csrfCookie.create(req, res, tokens[2]);
});
在路由处理程序中,我调用了这个函数,并在下一行调用了 res.send()
。
为了解决这个问题,我让 createTokensAndCookies
返回了一个承诺。所以我的代码是:
const createTokensAndCookies = catchAsync(async (req, res) => {
const promises = [];
promises.push(jwtToken.sign({ id: req.user._id }));
promises.push(jwtRefreshToken.create());
promises.push(csrfToken.create());
const tokens = await Promise.all(promises);
//create coookies
return new Promise((resolve, reject) => {
jwtCookie.create(req, res, tokens[0]);
jwtRefreshCookie.create(req, res, tokens[1]);
csrfCookie.create(req, res, tokens[2]);
resolve();
});
});
路由处理程序:
exports.signUp = catchAsync(async (req, res, next) => {
//get only certain variables out of req object
const { body } = req;
const user = await User.create({
name: body.name,
email: body.email,
password: body.password,
passwordConfirmation: body.passwordConfirmation,
});
req.user = user;
createTokensAndCookies(req, res).then(() => {
res.status(201).json({
status: 'success',
});
});
});
还有 catchAsync
包装器:
module.exports = (fn) => (req, res, next) => {
fn(req, res, next).catch(next);
};
我现在收到以下错误:
Cannot read property 'then' of undefined
有趣的是,当我删除 catchAsync
包装器时,一切正常,并且在创建所有 cookie 之前不会发送响应。
有谁知道如何在保持 catchAsync
翘曲器的同时做到这一点?解释为什么删除 catchAsync
包装器可以解决这个问题也很好。
答案 0 :(得分:1)
您的错误似乎发生在这一行:
createTokensAndCookies(req, res).then(() => {
问题在于 createTokensAndCookies()
不返回任何内容。解决此特定问题的一个简单修复方法可能是您像这样更改它以返回承诺:
module.exports = (fn) => (req, res, next) => {
return fn(req, res, next).catch(next);
};
但是,我认为主要问题是您在 catchAsync
中使用了 createTokensAndCookies
。请注意,您实际上传递了一个只有 2 个参数的函数,其中需要 3 个。捕捉两次似乎是多余的。您可以而且应该只在路由处理程序中传递从 createTokensAndCookies
(没有 catchAsync
)返回的承诺。所以删除catchAsync
:
const createTokensAndCookies = async (req, res) => {
const promises = [];
promises.push(jwtToken.sign({ id: req.user._id }));
promises.push(jwtRefreshToken.create());
promises.push(csrfToken.create());
const tokens = await Promise.all(promises);
//create cookies
jwtCookie.create(req, res, tokens[0]);
jwtRefreshCookie.create(req, res, tokens[1]);
csrfCookie.create(req, res, tokens[2]);
};
并像这样更改路由处理程序:
exports.signUp = catchAsync(async (req, res, next) => {
// ...
return createTokensAndCookies(req, res).then(() => {
res.status(201).json({
status: 'success',
});
});
});
我怀疑您想将 catchAsync
保留在 createCookiesAndTokens
中,因为您正在其他地方使用它作为路由处理程序。如果是这种情况,只需将其包装在 catchAsync
中即可。这样 createCookiesAndTokens
实际上会返回一个承诺,当出现问题时会失败。这是人们在阅读代码时所期望的,它使函数更具可重用性。