如何修复Node.js Express中的ERR_HTTP_HEADERS_SENT报错
问题修复方案
你遇到的[ERR_HTTP_HEADERS_SENT]错误根本原因是同一个HTTP请求中,向客户端返回了多次响应,Express 不允许这种操作。
具体错误点
你在server.js的GET /路由中存在两处核心错误:
- 先调用了
res.render('index'),该方法已经完成EJS模板渲染,把完整HTML响应返回给客户端,请求连接已经关闭 - 后续又调用了
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
相关产品推荐
相关产品推荐

