Node.js 初識 HTTP 模塊

一、實現“Hello World!”及相關API介紹


使用 HTTP 服務器和客戶端必須使用 require('http')


Node.js 中的 HTTP 接口設計主要是爲了支持 傳統的很難使用的多特性的協議,尤其是大量的信息。接口沒有緩衝整個接收和相應,用戶可使用流式數據。


HTPP信息的頭部是像一個對象那樣描述的:

{ 'content-length': '123',
  'content-type': 'text/plain',
  'connection': 'keep-alive',
  'host': 'mysite.com',
  'accept': '*/*' }



http.createServer([requestListener])

Returns: <http.Server>

返回一個新的 http.Server 的實例

requestListener 是一個自動添加 'request' 的函數



server.listen([port][, hostname][, backlog][, callback])

開始接受指定的端口號(port)和主機名(hostname)之間的連接。


參數類型:

port:Number

hostname:String

backlog:Number

callback:Function


如果省略了 hostname,當IPV6可用時,服務器將連接任意的IPV6地址(::),或者是任意的IPV4地址 (0.0.0.0)

忽略 port 參數或者使用 0 作爲端口號,如果想讓操作系統隨機分配一個端口號,可以在 'listening'

事件之後使用 server.address().port 來重新取回


如果想要監聽 unix 套接字,可以用一個文件名來替換 port 和 hostname


backlog 是連接請求隊列的最大長度,實際的長度將由你的 OS 通過系統調用設置來決定,比如 linux 上的 tcp_max_syn_backlog 和 somaxconn  。這個參數的默認值是511(不是512)


callback 作爲 'listening' 事件的一個監聽器, 是一個異步的回調函數



response.writeHead(statusCode[, statusMessage][, headers])

給請求消息發送一個響應頭


statusCode  Number 類型, 是一個三位數的 HTTP 狀態碼 比如:404

statusMessage  String 類型,是可選的,主要是提高可讀性

headers  Object 類型, 是一個響應頭,第二個參數是可選的


例如:

var body = 'hello world';response.writeHead(200, {
  'Content-Length': Buffer.byteLength(body),
  'Content-Type': 'text/plain' });


此方法在一個消息上只能調用一次,且必須在 response.end() 之前調用



response.end([data][, encoding][, callback])

這個方法是用來告訴服務器,所有的響應頭和響應主體已經發送完畢,服務器就會知道這個消息已經完成了。每一個響應消息都必須調用 response.end()



如果指定了 data ,就相當於在 response.end(callback) 之前調用了 response.write(data, encoding)

如果指定了 callback ,將在響應流結束之後調用



結合以上內容,我們再來看一下經典的 Node.js 入門案例,在頁面打印“Hello World”


基本的骨架:

//第一步: 引入 http 模塊
var http = require('http');

//第二步:創建一個服務器(requestListener 是一個函數,裏面有2個參數,一個請求消息,一個響應消息)
var server = http.createServer(function(req, res){

});

//第三步:服務器監聽本地的82端口
server.listen(8082, '127.0.0.1');


設置消息內容:

var server = http.createServer(function(req, res){
	//req -> request,表示請求; res -> response,表示響應

	//設置響應頭,第一個參數是3位數的HTTP狀態碼,第二個參數可選,第三個參數是一個對象,裏面可存放合法的MIME類型
	//MIME類型:文件類型是純文本,字符集編碼方式是 utf8
	res.writeHead(200,{'Content-Type': 'text/plain; charset=utf8'});
	//響應消息發送結束,如果指定了data參數,就相當於在 res.end() 之前添加了一個 res.end(data, encoding) 方法
	//res.end('Hello World!', 'utf8');
	res.end('Hello World!');
});


通過命令行工具掛起服務器,打開瀏覽器,在地址欄輸入: 127.0.0.1:8082

wKioL1hvDxrSL8bDAAANGVtZ_-A212.png

同時,也可以打開控制檯查看請求頭部

wKiom1hvD_bCV6QiAADoRDifsGY587.png

值得注意的是,如果省略了 res.end(), 頁面是渲染不出來的,因爲服務器會一直處於等待狀態,沒人告訴它響應消息是否結束了



在  Node.js 三大特點詳解  一文中,我們瞭解到傳統的 HTTP服務器一般建立在 Apache、Nginx、IIS等服務器上,而 Node.js 並不需要,由於 Node.js 提供了 http 模塊,自身就可以構建服務器(從上面的例子可以體會到)。


http 模塊 是通過 C++實現的,性能非常可靠,其中,封裝了一個 http 服務器 和一個簡易的 http 客戶端。http.Server 是一個基於事件的 http 服務器,http.request 則是一個 http 客戶端工具,用於向 http 服務器發起請求


前面提到的 http.createServer( requestListener ) 方法中,requestListener 是一個回調函數,函數有2個參數 request 和 response,request 是 http.IncomingMessage 對象的實例,response 是  http.ServerResponse 對象的實例。下面分別來學習 HTTP 服務器 和 HTTP 客戶端。



二、HTTP 服務器


先回顧下“Hello World!”這個例子

//第一步: 引入 http 模塊
var http = require('http');

//第二步:創建一個服務器(requestListener 是一個函數,裏面有2個參數,一個請求消息,一個響應消息)
var server = http.createServer(function(req, res){
	//req -> request,表示請求; res -> response,表示響應

	//設置響應頭,第一個參數是3位數的HTTP狀態碼,第二個參數可選,第三個參數是一個對象,裏面可存放合法的MIME類型
	//MIME類型:文件類型是純文本,字符集編碼方式是 utf8
	res.writeHead(200,{'Content-Type': 'text/plain; charset=utf8'});
	//響應消息發送結束,如果指定了data參數,就相當於在 res.end() 之前添加了一個 res.end(data, encoding) 方法
	//res.end('Hello World!', 'utf8');
	res.end('Hello World!');
});

//第三步:服務器監聽本地的82端口
server.listen(8082, '127.0.0.1');


基本的結構是直接創建一個 http 對象,然後創建一個 http 對象的實例 server,併爲其監聽82端口


1、http.Server

http.Server 繼承自 net.Server 而 net.Server是一個 EventEmitter,主要用來創建一個 TCP或者本地服務器。

事實上,Node.js 中大部分模塊都繼承自 EventEmitter,包括fs、net等模塊,這也是爲什麼說 Node.js 基於事件驅動。http.Server 提供的事件如下:


request

客戶端發出請求時觸發,每一次連接可能會發出很多個請求(假如是持久連接的話)。提供兩個參數request 和 response,是最常用的事件


connection

當 TCP 建立連接時,觸發此事件,提供一個參數 socket,是 net.socket 的實例


close

當服務器關閉時,觸發此事件。注意不是用戶斷開連接時


除此之外還有 checkContinue,upgrade,clientError 等事件,只有在實現複雜的 HTTP 服務器的時候纔會用到。


在這些事件中,最常用的就是 request 事件,所以,http 提供了一個捷徑:http.createServer( requestListener ),如我們所知,功能就是創建一個 HTTP 服務器並將 requestListener 作爲 request 事件的監聽函數,



2、http.IncomingMessage  --> request

http.IncomingMessage 是 HTTP 請求的信息,一般由 http.Server 的 request 事件發送,並作爲第一個參數傳遞,http 請求一般包括 請求頭部 和 請求主體。


其提供了三個事件用於控制請求體傳輸:

data: 當請求體數據到來時,觸發該事件。該事件提供一個參數 chunk,表示接收到的數據。如果該事            件沒有被監聽,那麼請求體將會被拋棄,該事件可能會被調用多次


end:當請求體數據傳輸完成時,該事件被觸發,此後將不會再有數據到來


close:用戶當前請求結束時,該事件被觸發。不同於end,如果用戶強制終止傳輸,也還是調用 close


http.IncomingMessage 的屬性如下:

wKioL1hvR16BhHqmAADs9DRRqnU593.png


3、http.ServerResponse   ---> response

http.ServerResponse 是返回給客戶端的信息,決定了用戶最終能看到的結果。它是由 http.Server 的 request 事件發送的,作爲第二個參數傳遞,一般簡稱爲 response 或 res


http.ServerResponse 有三個重要的成員函數,用於返回響應頭、響應內容以及結束請求(上面已經介紹過,這裏再複習一次)


response.writeHead(statusCode[, statusMessage][, 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 客戶端


http 模塊提供了兩個函數 http.request 和 http.get,功能是作爲客戶端向 HTTP 服務器發起請求


1、http.request(options, callback)  發起 HTTP 請求

接受兩個參數,options表示請求的參數,可以是一個對象或字符串,如果是字符串的話,將自動調用      url.parse() 解析;

callback 是請求的回調函數,需要傳遞一個參數


options 常用的參數如下:

host:請求網站的域名或 IP 地址

port:請求網站的端口號,默認 80

method:請求方法,默認是 GET

path:請求的相對於根的路徑,默認是“/”。QueryString 應該包含在其中,例如:/search?query=byvoid

headers:一個關聯數組對象,爲請求頭的內容


http.request() 返回一個 http.ClientRequest 的實例


示例代碼:

var http=require("http");

var options={
    hostname:"www.12306.cn",
    port:80
};

var req=http.request(options,function(res){
    res.setEncoding("utf-8");
    res.on("data",function(chunk){
        console.log(chunk.toString())
    });
    console.log(res.statusCode);
});
req.on("error",function(err){
    console.log(err.message);
});
req.end();


我們運行這段代碼,就可以在控制檯中看到 12036 的 HTML 代碼了

wKiom1hvUv3AJXl6AAD6X3woFm8991.png


2、http.get(options, callback) 

由於大多數的 GET 請求都沒有主體,所以 Node.js 提供了這個簡便的方法用於處理 GET 請求。

此方法是 http.request 的簡化版,唯一的區別在於 http.get 自動將請求方法設爲了 GET 請求,同時不需要手動調用 req.end()


var http = require('http');
http.get({host: 'www.12306.cn'}, function(res) {
    res.setEncoding('utf8');
    res.on('data', function (data) {
        console.log(data);
    });
});


運行這段代碼,一樣可以在控制檯得到 12036 的 HTML 代碼



3、http.ClientRequest

http.ClientRequest 是由 http.request 或 http.get 返回產生的對象,表示一個已經產生而且正在進行中的 HTTP 請求。

它提供了一個 response 事件,即 http.request 或 http.get,第二個參數指定的回調函數的綁定對象。我們可以顯示地綁定這個事件的監聽函數:


var http = require('http');
var req = http.get({host: 'www.12306.cn'});
req.on('response', function(res) {
    res.setEncoding('utf8');
    res.on('data', function (data) {
        console.log(data);
    });
});


運行這段代碼,一樣可以在控制檯得到 12036 的 HTML 代碼


http.ClientRequest 像 http.ServerResponse 一樣也提供了 write 和 end 函數,用於向服務器發送請求體,通常用於 POST、PUT 等操作。所有寫結束以後必須調用 end 函數以通知服務器,否則請求無效。


http.ClientRequest 還提供了以下函數。

request.abort():終止正在發送的請求。

request.setTimeout(timeout, [callback]):設置請求超時時間,timeout 爲毫秒數。當請求超時以後,callback 將會被調用。



4、http.ClientResponse


http.ClientResponse 與 http.ServerRequest 相似,提供了三個事件 data、end和 close,分別在數據到達、傳輸結束和連接結束時觸發,其中 data 事件傳遞一個參數chunk,表示接收到的數據。


http.ClientResponse 也提供了一些屬性,用於表示請求的結果狀態

wKioL1hvV4jCIDXNAABHJxPFLr4597.png


http.ClientResponse 還提供了以下幾個特殊的函數。


response.setEncoding([encoding]):設置默認的編碼,當 data 事件被觸發時,數據將會以 encoding 編碼。默認值是 null,即不編碼,以 Buffer 的形式存儲。常用編碼爲 utf8。


response.pause():暫停接收數據和發送事件,方便實現下載功能。


response.resume():從暫停的狀態中恢復。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章