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

Node.js登录场景触发ERR_HTTP_HEADERS_SENT错误,求代码排查方案

登录接口ERR_HTTP_HEADERS_SENT错误排查与解决

问题场景

输入错误用户名或密码后,再使用正确凭证登录,触发以下错误:

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at new NodeError (node:internal/errors:371:5)
    at ServerResponse.setHeader (node:_http_outgoing:576:11)
    at ServerResponse.header (D:\ecom website\ecom backend\node_modules\express\lib\response.js:794:10)
    at ServerResponse.send (D:\ecom website\ecom backend\node_modules\express\lib\response.js:174:12)
    at ServerResponse.json (D:\ecom website\ecom backend\node_modules\express\lib\response.js:278:15)
    at D:\ecom website\ecom backend\routes\auth.js:57:21
    at processTicksAndRejections (node:internal/process/task_queues:96:5) {
  code: 'ERR_HTTP_HEADERS_SENT'
}
[nodemon] app crashed - waiting for file changes before starting...

登录接口代码如下:

//LOGIN

router.post('/login', async (req, res) => {
  try {
    const user = await User.findOne({
      username: req.body.username,
    });

    !user && res.status(401).json('Wrong User Name');

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

    const inputPassword = req.body.password;

    originalPassword != inputPassword && res.status(401).json('Wrong Password');

    const accessToken = jwt.sign(
      {
        id: user._id,
        isAdmin: user.isAdmin,
      },
      process.env.JWT_SEC,
      { expiresIn: '3d' }
    );

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

问题原因

代码存在多次响应客户端请求的逻辑漏洞:

  • 当用户名错误时,执行!user && res.status(401).json('Wrong User Name')发送错误响应,但代码不会终止,后续仍会继续执行解密密码、生成Token等逻辑,最终触发res.status(200).json(...)再次发送响应,导致重复设置HTTP头。
  • 密码错误时同理,发送错误响应后代码继续执行到成功响应步骤,造成同一请求被多次响应。

HTTP协议要求一个请求只能对应一个响应,多次调用res.json()/res.send()会直接触发ERR_HTTP_HEADERS_SENT错误。

解决方法

在发送错误响应后,通过return终止函数执行,避免后续代码继续运行:

修改后的代码:

//LOGIN

router.post('/login', async (req, res) => {
  try {
    const user = await User.findOne({
      username: req.body.username,
    });

    // 用户名错误时返回并终止函数
    if (!user) {
      return res.status(401).json('Wrong User Name');
    }

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

    const inputPassword = req.body.password;

    // 密码错误时返回并终止函数
    if (originalPassword !== inputPassword) {
      return res.status(401).json('Wrong Password');
    }

    const accessToken = jwt.sign(
      {
        id: user._id,
        isAdmin: user.isAdmin,
      },
      process.env.JWT_SEC,
      { expiresIn: '3d' }
    );

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

关键修改点

  • 将原短路逻辑!user && ...改为if (!user) { return ... },确保发送错误响应后直接终止函数,不再执行后续代码。
  • 密码校验逻辑同理,用if判断加return,保证一次请求只发送一次响应。

内容的提问来源于stack exchange,提问作者Vlad Bocai

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 06:46:04