http
模块的官方示例`:
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!');
});
这里我发出一个 HTTP 请求,并在三种情况下报告:每当我开始接收 HTTP 响应时,每当我收到一些 HTTP 正文数据时,当响应完成时,以及所有错误时。
我希望此代码始终完成(除非连接挂起),日志中正好有一个
success!
或 error!
。但是,如果在服务器已经发送了一些标头之后连接重置,我会得到both。这是一个示例输出:
got response 200
got data: <Buffer 48 65 6c 6c 6f 0a>
ClientRequest error: Error: read ECONNRESET
error!
end body = Hello
complete = true
success!
如何复制:
nc -l -p 12345
启动调试服务器。node a.js
运行客户端。我在 Windows 上使用 node v18.14.2
,但我在 Ubuntu 22.04 上也看到了相同的行为 node v12.22.9
。nc
:
HTTP/1.1 200 OK
Hello
nc
进程或使用sudo tcpkill -i lo port 12345
终止TCP连接并向nc
(Linux)写入其他内容。似乎 Node 既检测到错误(因此
error
回调被触发)并认为 HTTP 请求成功(因此 end
回调被触发)。在我的原始代码中,导致我的应用程序的两个实例继续运行,而不是一个非常混乱。
如何确保其中一个被触发,并且仅在成功的 HTTP 响应时触发?
我建议看一下 once() 函数,它在被调用后会自行删除,这是它的参考链接 - https://nodejs.org/api/events.html#emitteronceeventname-listener