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

Express JS添加isAdm中间件后报[ERR_HTTP_HEADERS_SENT]错误如何解决

问题原因
    1. 中间件重复调用next():你在isAdm中间件中发起异步SQL查询后,没有阻断后续代码执行,会先执行if (jwtToken != '')块外的next(),第一次触发controller执行;等SQL异步回调返回后,又调用了一次next(true)/next(false),第二次触发controller执行,两次执行都会调用res.send返回响应,直接触发头重复设置的报错。
    1. next()传参用法错误:Express的next()只有传Error实例时会走错误处理中间件,传其他值不会传递给下游路由处理函数的参数,你controller定义的第三个bool参数根本拿不到中间件传的值,权限判断逻辑本身无效。
    1. 异常分支没有阻断响应:权限验证失败的场景应该直接在中间件返回401,不需要透传到controller处理。
修复方案

第一步:修改isAdm中间件

const sqladminchecker = require("../db/index");
const JWTTOKEN = require('jsonwebtoken')
require('dotenv').config() // 补充缺失的config调用,否则环境变量无法读取
const isAdmin = (req, res, next) => {
    let jwtToken = ''
    try {
        // 兼容cookie不存在的场景,避免split报错
        const cookies = req.headers.cookie?.split('; ') || []
        for (let i = 0; i < cookies.length; i++) {
            if (cookies[i].startsWith('jwt')) {
                jwtToken = cookies[i].split('=')[1]
                break
            }
        }
        // 无token直接返回401,不向下执行
        if (!jwtToken) {
            return res.status(401).send("Unauthorized")
        }
        const jwtData = JWTTOKEN.verify(jwtToken, process.env.JWT_SECRET)
        const { id } = jwtData
        sqladminchecker.query(
            "SELECT * FROM users WHERE id = ? AND isAdmin = ?",
            [id, 1],
            (err, reslt) => {
                // 查询报错/不是管理员直接返回401
                if (err || reslt.length !== 1) {
                    return res.status(401).send("Unauthorized")
                }
                // 验证通过,将管理员ID挂载到req对象方便后续使用
                req.adminId = id
                // 仅调用一次next放行
                next()
            }
        );
    } catch (e) {
        // 捕获JWT解析等异常直接返回401
        return res.status(401).send("Unauthorized")
    }
}
module.exports = isAdmin

第二步:简化controller逻辑,删除无效的bool判断

exports.create = (req, res) => {
  // Validate request
  if (!req.body) {
    return res.status(400).send({
      message: "Content can not be empty!"
    });
  }
  const crypto = require('crypto');
  const hash = crypto.createHash('md5').update(req.body.password).digest('hex');
  // 创建用户实例
  const user = new Users({
    username: req.body.username,
    password: hash,
    fullname: req.body.fullname
  });

  // 写入数据库
  Users.create(user, (err, data) => {
    if (err) {
      return res.status(500).send({
        message:
          err.message || "Some error occurred while creating the User."
      });
    }
    res.send(data);
  });
};
额外优化建议
  • 所有res.send/res.status调用前建议加return,避免后续逻辑意外执行
  • 密码加密不要用MD5,建议使用bcrypt等抗碰撞性更强的加密方案
  • 解析Cookie可以使用官方cookie-parser中间件,无需手动拆分字符串

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 18:45:03