刷新时出现Error [ERR_HTTP_HEADERS_SENT]的API认证问题求助
嘿,这个错误我太熟了!本质就是你的代码在一次请求里尝试多次发送HTTP响应给客户端——浏览器/客户端收到第一次响应后,服务器又想发第二次,自然就触发ERR_HTTP_HEADERS_SENT报错了。咱们来一步步拆解问题,然后修复它:
核心问题拆解
- 重复连接数据库+未终止错误流程:你每次请求都调用
con.connect(),而且当连接出错时,发送res.send()后没有终止后续代码执行,导致后面的con.query()还会继续运行,尝试再次发送响应。 - 查询回调参数缺失:
con.query()的回调只写了err参数,但实际上第二个参数才是查询结果result,这会导致result未定义,进而触发更多错误逻辑,多次调用响应方法。 - 响应后未终止代码:比如账号不存在时调用了
res.send(),但没加return,代码会继续走到后面的else分支,再次尝试发送响应。 - SQL注入风险:直接用字符串拼接邮箱参数到SQL语句里,这是非常危险的操作,必须改成参数化查询。
修复后的完整代码
// 建议提前初始化数据库连接(放在文件顶部,不要每次请求都连) // 示例: // const mysql = require('mysql'); // const con = mysql.createConnection({ // host: '你的主机', // user: '用户名', // password: '密码', // database: '数据库名' // }); // con.connect(err => { // if (err) throw err; // console.log("数据库连接成功!"); // }); app.get('/api/login', (req, res) => { const email = req.query.email; const password = req.query.password; // 先做参数校验,避免空参数直接查库 if (!email || !password) { return res.send({ success: false, message: '邮箱和密码不能为空' }); } // 用参数化查询避免SQL注入,?是安全占位符 con.query('SELECT * FROM users WHERE email = ?', [email], (err, result) => { if (err) { console.error('查询错误:', err); return res.send({ success: false, message: '查询失败' }); } if (result.length === 0) { return res.send({ success: false, message: '账号不存在' }); } // 验证密码 const isPasswordValid = bcrypt.compareSync(password, result[0].password); if (isPasswordValid) { // 注意:如果是前后端分离的API,建议返回JSON而非redirect(AJAX不会自动跳转) // return res.send({ success: true, message: '登录成功', data: { user: result[0] } }); // 如果你确实需要页面跳转,确保这是最后一个响应操作 return res.redirect('/dashboard'); } else { return res.send({ success: false, message: '密码错误' }); } }); });
关键修复点说明
- 提前初始化数据库连接:把数据库连接放在请求处理逻辑外面,只初始化一次,避免每次请求重复连接,减少出错概率。
- 参数校验前置:先检查邮箱和密码是否为空,提前终止无效请求,避免无意义的数据库查询。
- 参数化查询:用
?占位符代替字符串拼接,彻底规避SQL注入风险。 - 每个响应后加
return:确保发送响应后立即终止函数执行,不会走到后面的代码再次发送响应。 - 修正查询回调参数:补上
result参数,确保能正确获取数据库查询结果。
另外补充一句:如果你的前端是用AJAX/axios调用这个API,res.redirect()是无效的,因为AJAX不会自动跳转页面,这种情况下应该返回JSON响应,让前端自己处理跳转逻辑哦。
内容的提问来源于stack exchange,提问作者Han Wang
相关产品推荐
相关产品推荐

