如何确保Node.js HTTP客户端在ECONNRESET后仅触发一次回调
解决Node.js HTTP客户端连接重置时同时触发error和end回调的问题
问题描述
基于Node.js http模块编写的HTTP客户端代码,预期只会触发success!或error!其中一个逻辑,但当服务器返回响应头后TCP连接被重置(如ECONNRESET错误)时,两个回调会同时触发,导致业务逻辑重复执行。
原代码示例:
var http = require('http'); http.get('http://127.0.0.1:12345/', function(response) { console.log('got response ', response.statusCode); var body = []; response.on('data', function(data) { console.log('got data: ', data); }); response.on('end', function() { body = Buffer.concat(body).toString(); console.log('end body = ', body, ' complete = ', response.complete); console.log('success!'); }); }).on('error', function(err) { console.log('ClientRequest error: ' + err); console.log('error!'); });
问题场景:服务器返回响应头和部分/全部响应体后,TCP连接被强制断开,此时客户端会同时触发ClientRequest的error事件和response的end事件,导致success!和error!同时打印。
解决方案
核心思路是通过状态标记避免重复执行,同时结合response.complete判断响应是否完整接收,确保只有真正的成功场景才触发业务成功逻辑。
修改后的代码:
var http = require('http'); // 标记请求是否已处理完成,防止重复执行回调逻辑 let isCompleted = false; const req = http.get('http://127.0.0.1:12345/', function(response) { console.log('got response ', response.statusCode); const body = []; response.on('data', function(data) { console.log('got data: ', data); body.push(data); // 修复原代码遗漏的data存入逻辑 }); response.on('end', function() { if (isCompleted) return; // 仅当响应完全接收时,才判定为请求成功 if (response.complete) { const fullBody = Buffer.concat(body).toString(); console.log('end body = ', fullBody, ' complete = ', response.complete); console.log('success!'); } else { console.log('incomplete response received, error!'); } isCompleted = true; }); }); req.on('error', function(err) { if (isCompleted) return; // 若响应已完整接收,后续的连接重置错误不影响业务结果,直接忽略 if (req.res && req.res.complete) { console.log('connection reset after full response received, ignore error'); isCompleted = true; return; } console.log('ClientRequest error: ' + err); console.log('error!'); isCompleted = true; });
关键逻辑说明
- 状态锁
isCompleted:无论error或end事件哪个先触发,都会先检查该标记,已处理过的请求直接跳过后续逻辑,从根源避免重复执行。 - 响应完整性校验:在
end回调中通过response.complete判断响应是否完整接收,确保只有全部数据都收到时才触发成功逻辑。 - 错误过滤:在
error回调中,若发现响应已完整接收(req.res.complete为true),说明业务数据已经获取完成,此时的连接重置错误无需触发业务失败逻辑。
内容的提问来源于stack exchange,提问作者yeputons
相关产品推荐
相关产品推荐

