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'); });
错误原因
- 异步代码执行顺序混乱:
connection.query和bcrypt.hash都是异步操作,你在它们的回调未执行完成时,就调用了最后的res.redirect('/login'),导致先发送一次响应;后续回调里的res.redirect又尝试发送响应,触发重复发送响应的错误。 - 未阻止后续代码执行:即使在前面的分支里调用了
res.redirect,后续的哈希、插入数据库、重定向代码依然会执行,进一步加剧重复响应的问题。 - 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
相关产品推荐
相关产品推荐

