res.end與req.end之間的區別與聯繫(向本地服務器請求數據中遇到的問題)

前言

這是我在閱讀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(‘再見’) 呢?

猜想

針對這個問題,我提出了兩個猜想:

  1. 客戶端向服務器端發送了兩次請求
  2. 客戶端的 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.endreq.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');
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章