前言
這是我在閱讀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');