无法在承诺内调用 res.send()
Posted
技术标签:
【中文标题】无法在承诺内调用 res.send()【英文标题】:Cannot call res.send() within promise 【发布时间】:2020-03-24 18:10:49 【问题描述】:我正在使用回调重构我的代码。当然,第一个解决方案中的一切都按预期工作:
const newUser = new User(
email,
password,
)
User.exists( email , (err, userExists) =>
if (err)
return next(err)
if (userExists)
return res.status(400).send("A user with that email already exists")
newUser.save()
.then(result => console.log('new user successfully registered!:', result))
.catch(err =>
console.error('Cannot save user: ', err)
)
var profile = _.pick(req.body, 'email', 'password', 'extra')
res.status(201).send(
id_token: createIdToken(profile),
access_token: createAccessToken()
)
)
这是重构之后的:
User.exists( email )
.then(userExists =>
if (userExists)
res.status(400).send("A user with that email already exists")
)
.then(() =>
const newUser = new User(
email,
password,
)
return newUser
)
.then(newUser =>
console.log('newUser: ', newUser);
return newUser.save()
)
.then(result => console.log('new user successfully registered!:', result))
.catch(err =>
console.error('Cannot save user: ', err)
return next(err)
)
但是,这不起作用。我已经隔离出错误发生在承诺链中的哪个位置,并且当我尝试将响应发送回客户端res.send
我得到的错误是: C
无法保存用户:错误:发送后无法设置标题。 在 validateHeader (_http_outgoing.js:491:11) 在 ServerResponse.setHeader (_http_outgoing.js:498:3) 在 ServerResponse.header (/home/kyle/programming/projects/never-forget/server/node_modules/express/lib/response.js:771:10) 在 ServerResponse.send (/home/kyle/programming/projects/never-forget/server/node_modules/express/lib/response.js:170:12) 在/home/kyle/programming/projects/never-forget/server/src/controllers/users.js:47:22 在 在 process._tickDomainCallback (internal/process/next_tick.js:229:
cannot set headers after they are sent
是不言自明的,但我看不到在发送请求后我在程序的哪个位置尝试发送标头。看到res.send
结束了请求,我看不出还应该包括什么。
【问题讨论】:
您需要向我们展示整个请求处理程序的代码,以便我们发现您的错误。当您没有正确处理异步结果时,这是一个非常常见的错误。但是,我们需要查看整个请求处理程序以了解哪里出了问题。在重构代码中,对于成功的user.save()
,您不会发送任何响应,因此很明显该代码不会导致您看到的错误。我们需要看看剩下的代码。
【参考方案1】:
我能想到的问题是:
在回调实现中,当userExists
为真时,您正在调用return res.status(400).send("A user with that email already exists")
,这将结束回调并且res.status(201).send(...)
不会被调用。
但是,在promise实现中,当userExists
为真时,它们都会被调用。
所以,你可以在return res.status(400).send("A user with that email already exists")
之后抛出一个错误,并在catch 块中捕获它,它将结束主回调,即return next(err);
【讨论】:
我从未听说过 promise 的这种功能。尽管如此,我已经通过在条件中添加throw new Error('user already exists')
来尝试您建议的解决方案,但我仍然面临同样的问题。谢谢你看看【参考方案2】:
试试这个
User.exists( email )
.then(userExists =>
if (userExists.length >= 1)
return res.status(409).json(
message: "Mail exists"
);
else
newUser.save()
.then(result => console.log('new user successfully registered!:', result))
.catch(err =>
console.error('Cannot save user: ', err)
);
);
【讨论】:
感谢您的建议。不幸的是,和以前一样的错误仍然存在以上是关于无法在承诺内调用 res.send()的主要内容,如果未能解决你的问题,请参考以下文章
无法在vue端显示express res.send()自定义的错误信息。
在与 API 调用关联的函数中:未捕获(承诺中)类型错误:无法读取未定义的属性“包含”