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

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;

关键修改点

  1. 在所有res.render后添加return,确保错误分支代码执行终止,避免后续逻辑继续运行。
  2. 将bcrypt.hash嵌套到User.find的回调函数中,保证只有用户不存在时才执行密码哈希和用户创建操作。
  3. 修正用户存在判断为existingUser.length > 0,避免误判空数组为用户已存在。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 07:55:25