前言
这是我在阅读NodeJS权威指南一书时遇到的问题
代码
用于接受数据的HTTP服务器
var http = require('http');
var server = http.createServer(function(req,res){
if(req.url!=='/favicon.ico'){
req.on('data',function(data){
console.log('服务器端接收到数据:'+data);
res.end();
})
}
}).listen(1337,'127.0.0.1');
用于发送数据的HTTP客户端
var http = require('http');
var options = {
hostname:'localhost',
port:1337,
path:'/',
method:'POST'
};
var req = http.request(options);
req.write('你好');
req.end('再见')
结果
服务器端接收到数据:你好。
服务器端接收到数据:再见。
问题
我的问题在于,当客户端对服务器发起请求,并且用write发送数据时,将触发服务器端的data事件,而data事件中的res.end()方法将结束服务器与客户端之间的连接,
那么为什么断开连接之后,服务器还能收到 req.end(‘再见’) 呢?
猜想
针对这个问题,我提出了两个猜想:
- 客户端向服务器端发送了两次请求
- 客户端的 req.end(‘再见’) 的发送的比服务器端的 res.end() 的执行要来的快
验证
首先我们来验证第一个猜想:客户端向服务器端发送了两次请求
在一次连接中console.log(1)
var server = http.createServer(function(req,res){
if(req.url!=='/favicon.ico'){
console.log(1);
req.on('data',function(data){
console.log('服务器端接收到数据:'+data);
res.end()
})
}
}).listen(1337,'127.0.0.1');
发送了两个数据,只打出一个1,因此只进行了一次连接,那么猜想一显然不成立
那么我们再来验证第二个猜想:客户端的 req.end(‘再见’) 的发送的比服务器端的 res.end() 的执行要来的快
我们对客户端代码进行下列修改:给 **req.end(’再见’)**设置一个定时器,让它延迟两秒后再进行
var http = require('http');
var options = {
hostname:'localhost',
port:1337,
path:'/',
method:'POST'
};
var req = http.request(options);
req.write('你好')
setTimeout(function(){
req.end('再见')
},1000)
服务器只收到了一个你好,这说明,由于延迟了一秒,导致服务器端的 res.end() 方法提前于,客户端的 req.end(‘再见’) 方法执行,导致连接断开,客户端不能再将数据发送给服务器,从而我们可以推测,在这之前服务器能够接收到客户端的数据,是由于客户端的 req.end(‘再见’) 方法先于服务器的 res.end() 方法执行
那么我还有一个问题,res.end 和 req.end 两个方法的区别是什么?res.end标志着连接的断开,那么 req.end呢?如果 req.end不表示连接的断开,那么 req.end方法执行后,客户端还能向服务器发送数据吗?如果还可以的话,req.end方法的意义在哪里呢?
var http = require('http');
var options = {
hostname:'localhost',
port:1337,
path:'/',
method:'POST'
};
var req = http.request(options);
req.write('你好')
req.end('再见')
req.write('你好')
服务器报错了
那么req.end(‘再见’)后可以再利用req.end方法发送数据吗?
我们再req.end(‘再见’)后加上req.end(‘你好’)
var http = require('http');
var options = {
hostname:'localhost',
port:1337,
path:'/',
method:'POST'
};
var req = http.request(options);
req.write('你好')
req.end('再见')
req.end('你好')
显然,还是不行。这说明虽然req.end不能直接断开连接,但是却可以阻断数据的发送。
我们一般会在服务端设置一个req的end事件,当客户端的end事件发生时,将会触发该事件,代码如下所示,在下面的代码中,当触发了req的end事件之后,服务端就会执行res.end()方法,断开与客户端之间的连接
//用于接收数据的http服务器
var http = require('http');
var server = http.createServer(function(req,res){
if(req.url!=='/favicon.ico'){
console.log(1);
req.on('data',function(data){
console.log('服务器端接收到数据:'+data);
res.end()
})
req.on('end',function(){
res.end();
})
}
}).listen(1337,'127.0.0.1');