NodeJS的核心模塊http服務器端

HTTP服務器

http.Server是http模塊中的HTTP服務器對象,它提供了一套封裝級別很低的API,僅僅是流控制和簡單的消息解析,所有的高層功能都要通過它的接口來實現。
http.createServer創建一個http.Server的示例,將一個函數作爲HTTP請求處理函數。這個函數接受兩個參數,分別是請求對象(req)和響應對象(res)。

1.http.Server的事件
http.Server是一個基於事件的HTTP服務器,所有的請求都被封裝爲獨立的事件,開發者只需要對它的事件編寫響應函數即可實現HTTP服務器的所有功能。它集成自EventEmitter,提供了以下幾個事件。

  • request:當客戶端請求到來時,該事件被觸發,提供了兩個參數req和res,分別是http.ServerRequest和http.ServerResponse的實例,表示請求和響應信息。
  • connection:當TCP連接建立時,該事件被觸發,提供一個參數socket,爲net.Socket的實例。connection事件的粒度要大於request,因爲客戶端在Keep-Alive模式下可能會在同一個連接內發送多次請求。

2.http.ServerRequest
http.ServerRequest是HTTP請求的信息,是後端開發者最關注的內容。它一般由http.Server的request事件發送,作爲第一個參數傳遞,通常簡稱爲request或req。ServerRequest提供了一些屬性,見下表。

名稱 含義
complete 客戶端請求是否已經發送完成
httpVersion HTTP協議版本,通常是1.0或1.1
method HTTP請求方法,如get,post,put,delete等
url 原始的請求路徑,例如/static/image/x.jpg或/user?name=byvoid
headers HTTP請求頭
trailers HTTP請求尾(不常見)
connection 當前HTTP連接套接字,尾net.Socket的實例
socket connection屬性的別名
client client屬性的別名

HTTP請求一般可以分爲兩部分:請求頭(Request Header)和請求體(Request Body)。請求頭內容由於長度較短都可以在請求頭解析完成後立即讀取。而請求體可能相對較長,需要一定的事件傳輸,因此http.ServerRequest提供了一下3個事件用於控制請求體傳輸。

  • data:當請求體數據到來時,該事件被觸發。該事件提供一個參數chunk,表示接收到的數據。如果該事件沒有被監聽,那麼請求體將會被拋棄。該事件可能會被調用多次。
  • end:當請求體數據傳輸完成時, 該事件被觸發,此後,將不會再有數據到來。
  • close:用戶當前請求結束時,該事件被觸發。不用於end,如果用戶強制終止傳輸,也還是調用close。

3.獲取Get請求的內容
注意,http.ServerRequest提供的屬性中沒有類似於PHP語言中的GET _POST的屬性,那我們如何接受客戶端的表單請求呢?由於GET請求直接被嵌入在路徑中,URL是完整的請求路徑,包括了?後面的部分,因此你可以手動解析後面的內容作爲GET請求的參數。Node.js的url模塊中的parse函數提供了這個功能。例如:

//httpserverrequestget.js
var http = require('http');
var url = require('url');
var util = require('util');

http.createServer(function(req, res){
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end(util.inspect(url.parse(req.url, true)));
}).listen(3000);

我們可以看到瀏覽器返回的結果:

{
  search: '?name=byvoid&[email protected]',
  query: {name: 'byvoid', email: '[email protected]'},
  pathname: '/user',
  path: '/user?name=byvoid&[email protected]',
  href: '/user?name=byvoid&[email protected]'
}

通常url.parse,原始的path被解析爲一個對象,其中query就是我們所謂的GET請求的內容,而路徑則是pathname。

4.獲取 POST請求內容
HTTP協議1.1版本提供了8中標準的請求方法,其中最常見的就是GET和POST。相比GET請求把所有的內容編碼到訪問路徑中,POST請求的內容全部都在請求體中。http.ServerRequest並沒有一個屬性內容爲請求體,原因是等待請求體傳輸可能是一件耗時的工作,譬如上傳文件。而很多時候我們可能並不需要理會請求體的內容,惡意的POST請求會大大消耗服務器的資源。所以Node.js默認是不會解析請求體的,當你需要的時候,需要手動來做。讓我們看看實現方法:

//httpserverrequestpost.js
var http = require('http');
var querystring = require('querystring');
var util = require('util');

http.createServer(function(req, res){
  var post = '';
  req.on('data', function(chunk){
    post += chunk;
  });
  req.on('end', function(){
    post = querystring.parse(post);
    res.end(util.inspect(post));
  });
}).listen(3000);

上面代碼並沒有在請求響應函數中向客戶端返回信息,而是定義了一個post變量,用於在閉包中暫存請求體的細信息。通過req的data事件監聽函數,每當接收到請求體的數據,就累加到post變量中。在end事件觸發後,通過querystring.parse將post解析爲真正的post請求格式,然後向客戶端返回。

5.http.ServerResponse
http.ServerResponse是返回給客戶端的信息,決定了用戶最終能看到的結果。它也是由http.Server的request時間發送的,作爲第二個參數傳遞,一般簡稱爲resposne或res。
http.ServerResponse有三個重要的成員函數,用戶返回響應頭、響應內容以及結束請求。

  • response.writeHead(statusCode, [headers]):向請求的客戶端發送響應頭。statusCode是HTTP狀態嗎,如200(請求成功)、404(未找到)等。headers是一個類似關聯數組的對象,表示響應頭的每個屬性。該函數在一個請求內最多隻能調用一次,不過不調用,則自動生成一個響應頭。
  • response.write(data, [encoding]):向請求的客戶端發送響應內容。data是一個Buffer或字符串,表示要發送的內容。如果data是字符串,那麼需要制定encoding來說明它的編碼方式,默認是utf-8。在response.end調用之前,response.write可以被調用多次。
  • response.end([data], [encoding]):結束響應,告知客戶端所有發送已經完成。當所有要返回的內容發送完畢的時候,該函數必須被調用一次。它接受兩個可選參數,意義和response.write相同。如果不調用該函數,客戶端將永遠處於等待狀態。

總結
http的服務器端在接受用戶請求時,是通過事件觸發。request和connection事件,常用的是request事件。服務器端在向客戶端寫數據時,調用的是方法函數。有三個函數writeHeader、write、end。注意,在返回數據時,必須要調用end方法,否則客戶端會處於一直等待服務器返回數據的狀態。

發佈了130 篇原創文章 · 獲贊 64 · 訪問量 38萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章