You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Express登录接口try catch块中会出现未处理的Promise拒绝?

问题根源

你遇到的ERR_HTTP_HEADERS_SENT报错和未处理Promise拒绝的核心原因是:验证失败调用res.json()后没有终止代码执行,导致后续逻辑继续运行,尝试第二次发送HTTP响应。

问题出在两段短路判断代码上:

!user && res.status(401).json("Invalid credentials!");
originalPassword !== req.body.password && res.status(401).json("Invalid credentials!");

调用res.json()仅会把响应返回给客户端,并不会终止当前接口函数的执行,后续代码还是会继续向下运行:

  1. 如果用户名不存在,user为null,返回401响应后仍会执行CryptoJS.AES.decrypt(user.password,...),访问null的password属性直接抛出异常,触发catch块尝试再次发送500响应,就会触发响应头已发送的报错。
  2. 如果密码错误,返回401响应后仍会执行后续的res.status(200).json(others),同样会尝试二次发送响应触发报错。

解决方法

只需要在每个验证失败的分支调用res.json()后,增加return终止函数后续逻辑执行即可,修正后的代码如下:

router.post("/login", async (req, res) => {
  try {
    const user = await User.findOne({ username: req.body.username });
    if (!user) {
      return res.status(401).json("Invalid credentials!");
    }

    const hashedPassword = CryptoJS.AES.decrypt(
      user.password,
      process.env.PASS_SEC
    );

    const originalPassword = hashedPassword.toString(CryptoJS.enc.Utf8);
    if (originalPassword !== req.body.password) {
      return res.status(401).json("Invalid credentials!");
    }

    const { password, ...others } = user._doc;
    res.status(200).json(others);
  } catch (error) {
    res.status(500).json(error.message);
  }
});

修改后每个分支只会发送一次响应,不会再触发二次写响应头的逻辑,对应的Promise未处理异常也会同步消失。

内容的提问来源于stack exchange,提问作者Anthony Dinino

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 22:54:03