请求API时触发ERR_HTTP_HEADERS_SENT错误,求排查解决
解决 [ERR_HTTP_HEADERS_SENT] 错误:重复发送响应的问题
这个错误你肯定眼熟——本质就是同一个HTTP请求里,你尝试多次发送响应(比如多次调用res.json()),而HTTP协议要求一个请求只能对应一个响应。咱们来拆解你的代码问题,一步步修复:
问题根源
- 不必要的
forEach循环:你查询的是token='${token}',正常情况下token应该是唯一的,查询结果最多一条记录,但你用rows.forEach()遍历,只要有记录就会执行循环体里的逻辑。如果真的出现多条重复token(虽然不该发生),就会多次调用res.json(),直接触发错误。 - 异步操作的响应冲突:
pool.query()是异步Promise,你在forEach里调用它,即使你用了return res.json(),但外层的代码可能还会继续执行其他res.json()分支,比如else { res.json(...) },导致重复发送。 - SQL注入风险:直接把用户传入的
token和guildid拼进SQL语句,这是高危操作,别小看这个,很容易被攻击。
修复后的代码
router.get('/prefix', (req, res) => { // 先做参数校验,用res.status返回错误,而不是throw(避免未捕获异常) if (!req.query.token) { return res.status(400).json({ code: 400, message: 'NoTokenProvided' }); } if (!req.query.guildid) { return res.status(400).json({ code: 400, message: 'NoGuildIDProvided' }); } const token = req.query.token; const guildid = req.query.guildid; // 用参数化查询防SQL注入,PostgreSQL用$1占位符 const authSql = 'SELECT token FROM auth WHERE token = $1'; db.all(authSql, [token], (err, rows) => { if (err) { console.error('数据库查询错误:', err); return res.status(500).json({ code: 500, message: 'ErrorWithDatabase' }); } // 直接判断是否存在有效token,不需要循环 if (!rows[0]) { return res.status(401).json({ code: 401, message: 'That is not a valid token.' }); } // 验证token通过后,查询前缀,同样用参数化查询 pool.query('SELECT prefix FROM guild WHERE id = $1', [guildid]) .then(response => { if (!response.rows[0]) { return res.json({ code: 200, message: 'User has not setup a custom prefix.' }); } else { return res.json({ code: 200, prefix: response.rows[0].prefix }); } }) .catch(e => { console.error('前缀查询错误:', e); return res.status(500).json({ code: 500, message: 'Failed to fetch prefix' }); }); }); });
关键修改点说明
- 去掉
forEach循环:因为token是唯一标识,查询结果最多一条,直接用rows[0]判断即可,避免循环导致的多次响应。 - 每个响应都加
return:确保发送响应后立即终止后续代码执行,不会触发其他分支的res.json()。 - 替换为参数化查询:把用户输入作为参数传入,而不是直接拼进SQL,彻底杜绝SQL注入风险。
- 统一错误处理:用
res.status()设置正确的HTTP状态码,同时用return终止后续逻辑,避免错误后继续执行代码。 - 避免直接
throw:在Express路由里直接throw可能导致未捕获异常,最好用响应返回错误,或者配合全局错误处理中间件。
这样修改后,每个请求只会发送一次响应,ERR_HTTP_HEADERS_SENT错误就会消失,同时代码安全性和可读性也提升了。
内容的提问来源于stack exchange,提问作者Ajay Quirk
相关产品推荐
相关产品推荐

