POST请求后Node应用崩溃:用户注册逻辑异常排查
Express注册接口ERR_HTTP_HEADERS_SENT错误排查与修复
问题原因
- 未终止错误分支代码执行:当出现验证错误(如密码为空、确认密码不匹配)时,调用
res.render后未立即终止函数执行,后续的用户查询、密码哈希、用户创建逻辑仍会运行,导致多次向客户端发送响应头,触发ERR_HTTP_HEADERS_SENT错误。 - 异步操作无序执行:
User.find和bcrypt.hash均为异步函数,原代码中两者并行执行,即使检测到用户已存在,密码哈希和用户创建的逻辑仍会继续执行,最终导致重复创建用户。 - 用户存在判断逻辑错误:
User.find返回的是数组,空数组在JavaScript中属于truthy值,原代码if (existingUser)会误将空数组判定为用户已存在,正确判断应为检查数组长度existingUser.length > 0。
修复方案
调整异步操作顺序,在每个响应操作后添加return终止后续代码,修正用户存在判断逻辑:
var express = require('express'); const { body, validationResult } = require('express-validator'); var router = express.Router(); const bcrypt = require('bcryptjs'); const User = require('../models/user'); router.get('/', function(req, res, next) { res.render('index', { title: 'Messages' }); }); router.get('/sign-up', function(req, res, next) { res.render('sign-up', {title: 'sign up'}) }); router.post( '/sign-up', body('username', 'Username is required').trim().isLength({min:1}).escape(), body('password', 'Password is required').trim().isLength({min:1}).escape(), body('confPassword').custom((value, { req }) => { if (value !== req.body.password) { throw new Error('Password confirmation does not match password'); } return true; }), (req, res, next) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.render('sign-up', {title: 'Sign-up', errors: errors.errors}); } User.find({ 'username': req.body.username}).exec(function(err, existingUser){ if (err) { return next(err); } // 修正用户存在判断逻辑 if (existingUser.length > 0) { console.log(req.body.username) console.log(existingUser) return res.render('sign-up', {title: 'Sign-up', error: `${req.body.username} already exists in the system. Please choose another username`}); } // 仅当用户不存在时执行密码哈希与创建逻辑 bcrypt.hash(req.body.password, 10, (err, hashedPassword) => { if (err) { return next(err); } const user = new User({ username: req.body.username, password: hashedPassword }).save(err=> { if (err) { return next(err); } res.redirect("/"); }); }); }); } ) router.get('/sign-in', function(req, res, next) { res.render('sign-in', {}) }) module.exports = router;
关键修改点
- 在所有
res.render后添加return,确保错误分支代码执行终止,避免后续逻辑继续运行。 - 将
bcrypt.hash嵌套到User.find的回调函数中,保证只有用户不存在时才执行密码哈希和用户创建操作。 - 修正用户存在判断为
existingUser.length > 0,避免误判空数组为用户已存在。
内容的提问来源于stack exchange,提问作者Adildo
相关产品推荐
相关产品推荐

