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

调用登录API时出现ERR_HTTP_HEADERS_SENT错误求助

MERN项目登录接口报错:Error [ERR_HTTP_HEADERS_SENT]

我正在制作首个MERN项目,登录前可正常从MongoDB获取数据,但提交登录表单时触发错误:Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client。已搜索4小时仍未找到重复发送响应头的原因,以下是相关代码及错误栈信息,恳请帮助排查问题。

错误栈信息

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at new NodeError (node:internal/errors:372:5)
at ServerResponse.setHeader (node:_http_outgoing:576:11)
at ServerResponse.header (E:\Blog-Website\api\node_modules\express\lib\response.js:794:10)
at ServerResponse.send (E:\Blog-Website\api\node_modules\express\lib\response.js:174:12)
at ServerResponse.json (E:\Blog-Website\api\node_modules\express\lib\response.js:278:15)
at E:\Blog-Website\api\routes\auth.js:37:23
at processTicksAndRejections (node:internal/process/task_queues:96:5) { 
code: 'ERR_HTTP_HEADERS_SENT'

后端auth.js代码

const router = require("express").Router();
const User = require("../models/User");
const bcrypt = require('bcrypt');

//REGISTER
router.post("/register", async (req, res) => {
  try {
    const salt = await bcrypt.genSalt(10);
    const hashedPass = await bcrypt.hash(req.body.password, salt);
    const newUser = new User({
      username: req.body.username,
      email: req.body.email,
      password: hashedPass,
    });

    const user = await newUser.save();
    console.log(user)
    res.status(200).json(user);
  } catch (err) {
    res.status(500).json(err);
  }
});

//LOGIN
router.post("/login", async (req, res) => {
  try {
    const user = await User.findOne({ username: req.body.username });
    !user && res.status(400).json("Wrong credentials!");

    const validated = await bcrypt.compare(req.body.password, user.password);
    !validated && res.status(400).json("Wrong credentials!");

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

module.exports = router

前端login.jsx代码

import { Link } from "react-router-dom";
import "./login.css"
import { useContext, useRef } from "react";
import axios from "axios";
import { Context } from "../../../context/Context";

export default function Login() {
  const userRef = useRef();
  const passwordRef = useRef();
  const { user, dispatch, isFetching } = useContext(Context);

  const handleSubmit = async (e) => {
    e.preventDefault();
    dispatch({ type: "LOGIN_START" });
    try {
      const res = await axios.post("/auth/login", {
        username: userRef.current.value,
        password: passwordRef.current.value,
      });
      dispatch({ type: "LOGIN_SUCCESS", payload: res.data });
    } catch (err) {
      dispatch({ type: "LOGIN_FAILURE" });
    }
  };

  console.log(user)

  return (
    <div className="login">
      <span className="loginTitle">Login</span>
      <form className="loginForm" onSubmit={handleSubmit}>
        <label>Username</label>
        <input className="loginInput" type="text" placeholder="Enter your username..." ref={userRef} />
        <label>Password</label>
        <input className="loginInput" type="password" placeholder="Enter your password..." ref={passwordRef} />
        <button className="loginButton" type="submit">Login</button>
      </form>
      <button className="loginRegisterButton">
        <Link className="link" to="/register">Register</Link>
      </button>
    </div>
  );
}

问题原因及修复

错误根源在login接口的逻辑判断:当!user或!validated时,你用&&直接发送响应,但未终止后续代码执行。比如用户不存在时,!user && res.status(400).json("Wrong credentials!")发送一次响应后,代码仍会继续执行,尝试访问user.password(此时user为undefined,触发catch),catch里又发送一次500响应,导致重复发送响应头。

修复方法:发送错误响应后用return终止函数,或改用if-else结构:

修复后的login接口代码

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

    const validated = await bcrypt.compare(req.body.password, user.password);
    if (!validated) {
      return res.status(400).json("Wrong credentials!");
    }

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

通过if判断加return,确保发送错误响应后直接结束函数,避免后续代码执行引发的重复响应问题。

内容的提问来源于stack exchange,提问作者Raghav Mittal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 14:36:26