无法在承诺内调用 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()自定义的错误信息。

JavaScript将回调转换为承诺[重复]

PromiseKit 无法在链中命中

在与 API 调用关联的函数中:未捕获(承诺中)类型错误:无法读取未定义的属性“包含”

在POST请求结束之前无法访问最近保存的数据 - node.js

未捕获(承诺)错误:请求失败,状态码为500