Express.js中EventEmitter触发500错误,多请求仅首次返回200问题排查
问题成因与解决方法:ERR_HTTP_HEADERS_SENT错误
问题成因
这个错误我之前也碰到过,核心原因是全局事件发射器的监听器没有被正确清理,具体细节如下:
- 你创建的
emmiter是全局变量,所有请求共享同一个事件发射器实例。 - 每次处理
/my-route的POST请求时,都会通过emmiter.on()给ok和fail事件添加新的监听器,这些监听器不会自动被移除。 - 当后续请求触发事件时,所有之前绑定的监听器都会被执行——旧监听器里的
res对象对应的是已经完成的请求,这时候调用res.json()就会尝试给已结束的请求发送响应,自然就会抛出Cannot set headers after they are sent to the client的错误。 - 另外还有个小疏漏:原代码里
res.json({status:fail})中的fail是未定义变量,应该改成false,否则还会触发额外的报错。
解决方法
这里提供三种可行的解决方案,你可以根据自己的场景选择:
方案1:使用一次性监听器once()
once()方法绑定的监听器只会执行一次,执行后会自动从事件发射器上移除,完美解决监听器残留问题:
express.post('/my-route',function(req,res,next){ emmiter.once('ok',function(){ res.json({status:true}) }); emmiter.once('fail',function(){ res.json({status:false}) // 修正未定义的fail变量为false }); emmitFunctionality(req.message); })
方案2:手动移除监听器
如果需要复用监听器逻辑,可以在监听器执行后手动移除绑定:
express.post('/my-route',function(req,res,next){ // 定义监听器函数,方便后续移除 const handleOk = () => { res.json({status:true}); emmiter.off('ok', handleOk); emmiter.off('fail', handleFail); }; const handleFail = () => { res.json({status:false}); emmiter.off('ok', handleOk); emmiter.off('fail', handleFail); }; emmiter.on('ok', handleOk); emmiter.on('fail', handleFail); emmitFunctionality(req.message); })
方案3:每个请求使用独立的EventEmitter实例
如果不需要跨请求共享事件发射器,直接在请求处理函数内部创建新的实例,从根源上避免监听器交叉:
express.post('/my-route',function(req,res,next){ // 每个请求创建独立的事件发射器 const emmiter = new EventEmitter(); // 将发射函数移到内部,使用当前请求的发射器 const emmitFunctionality = function(message){ if(message==='hello'){ return emmiter.emit("ok") } return emmiter.emit("fail"); } emmiter.on('ok',function(){ res.json({status:true}) }); emmiter.on('fail',function(){ res.json({status:false}) }); emmitFunctionality(req.message); })
内容的提问来源于stack exchange,提问作者Dimitrios Desyllas
相关产品推荐
相关产品推荐

