每天學點node系列-http

一半水一半冰發表於2019-07-08

任何可以使用JavaScript來編寫的應用,最終會由JavaScript編寫。--Atwood's Law

http模組概覽

http模組主要用於建立http server服務,並且

  • 支援更多特性
  • 不緩衝請求和響應
  • 能夠流式傳輸資料

藉助http模組,可以幾行程式碼就搞定一個超迷你的web server:

var http=require("http")
http.createServer(function(req, res){
    res.writeHead(200,{
        "content-type":"text/plain"
    })
    res.write("hello nodejs")
    res.end()
}).listen(3000)

http伺服器

像上面一樣使用的createServer方法返回了一個http.Server物件,這其實是一個建立http服務的捷徑,如果我們用以下程式碼來實現的話,也將一樣可行

var http = require("http")
var server = new http.Server()
server.on("request", function(req, res){
        res.writeHead(200, {
        "content-type":"text/plain"
    })
    res.write("hello nodejs")
    res.end()
})
server.listen(3000)

以上程式碼是通過直接建立一個http.Server物件,然後為其新增request事件監聽,其實也就說createServer方法其實本質上也是為http.Server物件新增了一個request事件監聽。

http.Server的事件

http.Server繼承自 net.Server,http.Server提供的事件如下:

  • request:當客戶端請求到來時,該事件被觸發,提供兩個引數req和res,表示請求和響應資訊,是最常用的事件
  • connection:當TCP連線建立時,該事件被觸發,提供一個引數socket,是net.Socket的例項
  • close:當伺服器關閉時,觸發事件(注意不是在使用者斷開連線時)

正如上面我們所看到的request事件是最常用的,而引數req和res分別是http.IncomingMessage和http.ServerResponse的例項,那麼我們來看看這兩個類

http.IncomingMessage

在server端:獲取請求傳送方的資訊,比如請求方法、路徑、傳遞的資料等。
在client端:獲取 server 端傳送過來的資訊,比如請求方法、路徑、傳遞的資料等。

http.IncomingMessage例項 有三個屬性需要注意:method、statusCode、statusMessage。

  • method:只在 server 端的例項有(也就是 serverReq.method)
  • statusCode/statusMessage:只在 client 端 的例項有(也就是 clientRes.method)

並且其提供了3個事件,如下

  • data:當請求體資料到來時,該事件被觸發,該事件提供一個引數chunk,表示接受的資料,如果該事件沒有被監聽,則請求體會被拋棄,該事件可能會被呼叫多次(這與nodejs是非同步的有關係)
  • end:當請求體資料傳輸完畢時,該事件會被觸發,此後不會再有資料
  • close:使用者當前請求結束時,該事件被觸發,不同於end,如果使用者強制終止了傳輸,也是用close

http.ServerResponse

http.ServerResponse 的作用很明確,服務端通過http.ServerResponse 例項,來個請求方傳送資料。包括髮送響應表頭,傳送響應主體等。它決定了使用者最終看到的內容,一般也由http.Server的request事件傳送,並作為第二個引數傳遞,它有三個重要的成員函式,用於返回響應頭、響應內容以及結束請求

  • res.writeHead(statusCode,[heasers]):向請求的客戶端傳送響應頭,該函式在一個請求中最多呼叫一次,如果不呼叫,則會自動生成一個響應頭
  • res.write(data,[encoding]):想請求的客戶端傳送相應內容,data是一個buffer或者字串,如果data是字串,則需要制定編碼方式,預設為utf-8,在res.end呼叫之前可以多次呼叫
  • res.end([data],[encoding]):結束響應,告知客戶端所有傳送已經結束,當所有要返回的內容傳送完畢時,該函式必需被呼叫一次,兩個可選引數與res.write()相同。如果不呼叫這個函式,客戶端將用於處於等待狀態。

http客戶端

http模組提供了兩個函式http.request和http.get,功能是作為客戶端向http伺服器發起請求。

var http = require('http')

// http server
var server = http.createServer(function(req, res){
    var url = req.url
    res.end( '您訪問的地址是:' + url )
})

server.listen(3000)

// http client
var client = http.get('http://127.0.0.1:3000', function(res){
    res.setEncoding("utf-8")
    res.on("data",function(chunk){
        console.log(chunk.toString()) 
    })
    console.log(res.statusCode);
})

client.on("error",function(err){ 
    console.log(err.message)
})
client.end()

http.ClientRequest

此物件由 http.request() 內部建立並返回。 它表示正在進行的請求,且其請求頭已進入佇列。 請求頭仍然可以使用 setHeader(name, value)getHeader(name)removeHeader(name) 改變。 實際的請求頭將與第一個資料塊一起傳送,或者當呼叫 request.end() 時傳送。
要獲得響應,則為請求物件新增 'response' 事件監聽器。 當接收到響應頭時,將、則會從請求物件觸發 'response' 事件。 'response' 事件執行時有一個引數,該引數是 http.IncomingMessage 的例項。

'response' 事件期間,可以新增監聽器到響應物件,比如監聽 'data' 事件。

如果沒有新增 'response' 事件處理函式,則響應將被完全丟棄。 如果新增了 'response' 事件處理函式,則必須消費完響應物件中的資料,每當有 'readable' 事件時呼叫 response.read()、或新增 'data' 事件處理函式、或通過呼叫 .resume() 方法。 在消費完資料之前,不會觸發 'end' 事件。 此外,在讀取資料之前,它將佔用記憶體,最終可能導致程式記憶體不足的錯誤。

Node.js 不檢查 Content-Length 和已傳輸的主體的長度是否相等。

請求繼承自流,且額外實現以下內容:

  • 'abort': 當請求被客戶端中止時觸發。 此事件僅在第一次呼叫 abort() 時觸發。
  • 'timeout':當底層套接字因不活動而超時時觸發。 這隻會通知套接字已空閒。 必須手動中止請求。
  • ...

相關文章