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

如何修复Node.js Express中的ERR_HTTP_HEADERS_SENT报错

问题修复方案

你遇到的[ERR_HTTP_HEADERS_SENT]错误根本原因是同一个HTTP请求中,向客户端返回了多次响应,Express 不允许这种操作。


具体错误点

你在server.js的GET /路由中存在两处核心错误:

  1. 先调用了res.render('index'),该方法已经完成EJS模板渲染,把完整HTML响应返回给客户端,请求连接已经关闭
  2. 后续又调用了res.json(array),尝试给已经结束的请求再返回一次JSON响应,直接触发报错

同时还存在几个隐藏问题:

  • MySQL的con.query是异步操作,你当前的写法不等数据库查询结果返回就执行res.json,拿到的永远是空数组或之前请求残留的数据
  • 定义了全局的array变量存储查询结果,多用户同时请求时会出现数据重复、错乱
  • 代码直接使用PORT变量但没有定义,启动服务会报错
  • POST /add路由的数据库插入操作是异步的,当前写法不管插入成功失败都会直接返回页面,无法给出正确错误提示

修复后的完整代码

server.js

const express = require('express')
const mysql = require('mysql')
const cors = require('cors')
const app = express()
// 定义PORT变量,优先读取环境变量,默认3000
const PORT = process.env.PORT || 3000

const parser = express.urlencoded({extended:false})
app.use(cors())
app.set('view engine', 'ejs')
app.use(express.static('public'));

const con = mysql.createConnection({
    host: "localhost",
    user: "root",
    password: "",
    database: "expenseapp"
})
con.connect(err=>{
    if(err)
        throw err;
    console.log('connected!');
})

// 删掉全局array变量,避免多请求数据污染
app.get('/',(req,res)=>{
    let queryName = "SELECT * from `expenses`";
    con.query(queryName, (err, result)=>{
        if(err)
            throw err
        // 如果需要渲染页面同时传递数据,直接把数据传给EJS模板
        res.render('index', {expenses: result})
        // 如果只需要返回JSON数据,删掉上面的res.render,启用下面这句
        // res.json(result)
    })
})
app.get('/add', (req,res)=>{
    res.render('add')
})
app.post('/add', parser, (req,res)=>{
    let data = [req.body.product, req.body.cost]
    let sqlquery = "INSERT INTO `expenses` (name, cost) VALUES (?)";
    con.query(sqlquery, [data], (err, result)=>{
        if(err)
            throw err
        console.log("saved new product");
        // 响应逻辑放到数据库操作回调中,确保插入成功后再返回
        res.render('add')
    })
})

app.listen(PORT, ()=>console.log(`Server's running on PORT ${PORT}`))

额外适配方案

如果你的前端app.js需要单独调用接口拿JSON数据,可以新增独立的接口路由,不要和页面渲染路由混用:

// 专门给前端提供数据的接口
app.get('/api/expenses', (req, res) => {
    let queryName = "SELECT * from `expenses`";
    con.query(queryName, (err, result)=>{
        if(err) return res.status(500).json({error: '查询失败'})
        res.json(result)
    })
})

前端app.js直接请求/api/expenses即可拿到正常的JSON数据。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 02:27:01