Express服务端重定向报Cannot set headers after they are sent错误如何解决
错误触发原因
- 根本原因是同一请求上下文内重复发送响应:Express规定一个请求只能返回一次响应,只要调用了
res.redirect()/res.render()/res.send()这类响应方法后,再次调用同类方法就会抛出该错误。 - 你的代码具体触发场景:
Room.findById()是异步IO操作,你使用了回调写法,而next()直接写在异步操作外部,不等查询结果返回就直接执行next()调用后续路由逻辑,后续路由里的res.render('room')会先完成响应发送。- 等Mongoose查询完成触发回调时,又执行了
res.redirect('/'),此时响应已经发送给客户端,自然触发报错。 - 额外逻辑错误:当前回调写法不管ID是否存在、查询是否成功,都会执行重定向,不符合你「仅ID不存在时重定向」的需求。
修复方案
建议直接用async/await写法替代回调,逻辑更清晰,也避免异步时序问题,修改后的代码如下:
修正后的中间件代码
const mongoose = require('mongoose'); const Room = require('./model/room'); module.exports.isOnDB = async (req, res, next) => { const { id } = req.params; try { // 校验id是否是合法的MongoDB ObjectId,避免无效id查询报错 if (!mongoose.Types.ObjectId.isValid(id)) { return res.redirect('/'); } const room = await Room.findById(id); // 仅查不到对应文档时重定向 if (!room) { return res.redirect('/'); } // 可选优化:把查到的room挂载到req上,后续路由直接使用无需重复查询 req.room = room; // 校验通过才调用next执行后续逻辑 next(); } catch (err) { // 查询出错时重定向到首页,也可根据自身需求调整错误处理逻辑 return res.redirect('/'); } };
修正后的路由代码(可选优化)
const { isOnDB } = require('../middleware'); router.get('/', (req, res) => { res.render('layouts/boilerplate'); }); router.get('/room/:id', isOnDB, (req, res) => { // 可直接使用中间件挂载的req.room,无需重复查询 res.render('room', { roomId: req.params.id, room: req.room }); });
内容的提问来源于stack exchange,提问作者Noob Gaming
相关产品推荐
相关产品推荐

