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

Node.js Post请求路由设置报错:ERR_HTTP_HEADERS_SENT

注册接口出现 ERR_HTTP_HEADERS_SENT 错误

错误日志

node:_http_outgoing:648
    throw new ERR_HTTP_HEADERS_SENT('set');
    ^

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at new NodeError (node:internal/errors:405:5)
    at ServerResponse.setHeader (node:_http_outgoing:648:11)
    at ServerResponse.header (D:\Backend\FinallyAWorkingProject\node_modules\express\lib\response.js:794:10)
    at ServerResponse.location (D:\Backend\FinallyAWorkingProject\node_modules\express\lib\response.js:915:15)
    at ServerResponse.redirect (D:\Backend\FinallyAWorkingProject\node_modules\express\lib\response.js:953:18)
    at Query.onResult (D:\Backend\FinallyAWorkingProject\serverTestingRegister.js:76:17)
    at Connection._notifyError (D:\Backend\FinallyAWorkingProject\node_modules\mysql2\lib\connection.js:228:21)
    at Connection._handleFatalError (D:\Backend\FinallyAWorkingProject\node_modules\mysql2\lib\connection.js:183:10)
    at Connection.handlePacket (D:\Backend\FinallyAWorkingProject\node_modules\mysql2\lib\connection.js:488:12)
    at PacketParser.onPacket (D:\Backend\FinallyAWorkingProject\node_modules\mysql2\lib\connection.js:97:12) {
  code: 'ERR_HTTP_HEADERS_SENT'
}

相关代码

//Creating the express app and hosting it locally
const express=require('express');
const app=express();
const bcrypt=require('bcrypt');
const mysql=require('mysql2');
const flash=require('express-flash');
const session=require('express-session');


// Load environment variables from .env file
require('dotenv').config();
const port= process.env.PORT ;
const host= process.env.DB_HOST;
const user= process.env.DB_USER;
const db_name=process.env.DB_NAME;
const pass=process.env.DB_PASSWORD;
const sec=process.env.SECRET_SESSION;


app.listen(port);


////Creating a database connection object
const connection = mysql.createConnection({
    host: host,
    user: user,
    password: pass,
    database: db_name
});
connection.connect();

// Setting up the view engine (ejs)
app.set('view engine', 'ejs');
//setting up middlewares
app.use(session({
    secret: sec, // Replace with a strong secret key
    resave: false,
    saveUninitialized: false
}));
app.use(express.urlencoded({extended: false}));
app.use(flash());

////Routing
app.get('/',(req,res)=>{
    res.render('index.ejs');
});

app.get('/login',(req,res)=>{
    res.render('login.ejs');
});

app.get('/register',(req,res)=>{
    res.render('register.ejs');
});

app.post('/register',(req,res)=>{
    const {name,email,password,cpassword}=req.body;
    if(password!=cpassword){
    req.flash('error', 'Passwords do not match');
    res.redirect('/register');}
    ////Setting a query to check if an email already exist
    else{
    connection.query('select * from users where email=?',[email],(error,results)=>{
        if(error){
            req.flash('error', 'An error occurred');
            res.redirect('/register');        }
        if(results.length> 0 ){
            req.flash('error', 'Email already exists');
            res.redirect('/register');
        }
    });}
    const hashedpassword=bcrypt.hash(password,12);
    connection.query('insert into users values (?,?,?)',[name,email,hashedpassword],(error,results)=>{
        if(error){
            req.flash('error', 'Error accquired,Pls try again in a minute');
            res.redirect('/register');        }
    });
    res.redirect('/login');
});

错误原因

  1. 异步代码执行顺序混乱:connection.query 和 bcrypt.hash 都是异步操作,你在它们的回调未执行完成时,就调用了最后的 res.redirect('/login'),导致先发送一次响应;后续回调里的 res.redirect 又尝试发送响应,触发重复发送响应的错误。
  2. 未阻止后续代码执行:即使在前面的分支里调用了 res.redirect,后续的哈希、插入数据库、重定向代码依然会执行,进一步加剧重复响应的问题。
  3. bcrypt.hash 使用错误:bcrypt.hash 返回的是 Promise 对象,直接赋值给 hashedpassword 会导致插入数据库的不是正确的密码哈希字符串。

解决方案

改用 async/await 处理异步操作,确保代码按顺序执行,且每个响应发送后阻止后续代码执行:

修改后的代码

// ... 其他代码保持不变 ...

// 将路由处理函数改为 async
app.post('/register', async (req,res)=>{
    const {name,email,password,cpassword}=req.body;

    // 密码不匹配校验
    if(password!=cpassword){
        req.flash('error', 'Passwords do not match');
        return res.redirect('/register'); // 加return阻止后续代码执行
    }

    try {
        // 检查邮箱是否已存在(mysql2 支持通过.promise()转为Promise)
        const [results] = await connection.promise().query('select * from users where email=?',[email]);
        if(results.length> 0 ){
            req.flash('error', 'Email already exists');
            return res.redirect('/register');
        }

        // 等待密码哈希完成
        const hashedpassword = await bcrypt.hash(password,12);

        // 插入用户数据
        await connection.promise().query('insert into users values (?,?,?)',[name,email,hashedpassword]);

        // 所有操作完成后重定向到登录页
        res.redirect('/login');
    } catch (error) {
        // 统一捕获所有异步操作错误
        req.flash('error', 'Error occurred, please try again later');
        return res.redirect('/register');
    }
});

关键修改点

  • 将路由处理函数标记为 async,使用 await 处理所有异步操作,让代码按顺序执行。
  • 每个 res.redirect 前添加 return,确保发送响应后不再执行后续代码。
  • 使用 try/catch 统一捕获异步操作中的错误,避免分散处理导致的遗漏。
  • 正确等待 bcrypt.hash 完成,获取真实的哈希值再插入数据库。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 21:47:39