Node.js學習筆記5【http伺服器與客戶端】
Node.js標準庫提供了http模組,其中封裝了一個高效的HTTP伺服器和一個簡易的HTTP客戶端。http.Server是一個基於事件的http伺服器,它的核心由Node.js下層C++部分實現,而介面由javascript封裝,兼顧了高效能與簡易性。http.request則是一個http客戶端工具,用於向http伺服器發起請求,如內容抓取。
http伺服器
http.Server是http模組中的HTTP伺服器物件,用Node.js做的所有基於HTTP協議系統,如網站、社交應用甚至代理伺服器,都是基於http.Server實現的。它提供了一套封裝級別很低的API,僅僅是流控制和簡單的訊息解析,所有高層功能都要通過它的介面來實現。如:
//app.js
var http =require(‘http’);
http.createServer(function(req,res){
res.writeHead(200,{‘Content-Type’:’text/html’});
res.write(‘<h1>Node.js</h1>’);
res.end(‘<p>Hello World</p>’);
}).listen(3000);
console.log(“HTTPserver is listening at port 3000.”);
1.http.Server的事件
http.Server是一個基於事件的HTTP伺服器,所有的請求都被封裝為獨立的事件,開發者只需要對它的事件編寫響應函式即可實現HTTP伺服器的所有功能。它繼承自EventEmitter,提供了以下幾個事件。
l request:當客戶端請求到來時,該事件被觸發,提供兩個引數req和res,分別是http.ServerRequest和http.ServerResponse的例項,表示請求和響應資訊。
l connection:當TCP連線建立時,該事件被觸發,提供一個引數socket,為net.Socket的例項。connection事件的粒度要大於request,因為客戶端在Keep-Alive模式下可能會在同一個連線內傳送多次請求。
l close:當伺服器關閉時,該事件觸發。注意不是在使用者連線斷開時。
除此之外還有checkContinue、upgrade、clientError事件,通常我們不需要關心,只有實現複雜的HTTP伺服器的時候才會用到。
在這些事件中,最常用的就是request了,因此http提供了一個捷徑:http.createServer([requestListener]),功能是建立一個HTTP伺服器並將requestListener作為request事件的監聽函式,這也是上面例子中的實現方式
下面是顯式方式註冊request事件:
//httpserver.js
var http =require(‘http’);
var server = http.Server();
sever.on(‘request’,function(req,res){
res.writeHead(200,{‘Content-Type’:’text/html’});
res.write(‘<h1>Node.js</h1>’);
res.end(‘<p>Hello World</p>’);
});
sever.listen(3000);
console.log(“HTTPserver is listening at port 3000.”);
2.http.ServerRequest
http.ServerRequest是HTTP請求的資訊,是後端開發者最關注的內容。它一般由http.Server的request事件傳送,作為第一個引數傳遞,通常簡稱為request或req。
屬性有:
名稱 |
含義 |
complete |
客戶端請求是否已經發送完成 |
httpVersion |
HTTP協議版本,通常是1.0或1.1 |
method |
HTTP請求方法,如GET POST PUT DELETE |
url |
原始請求路徑 |
headers |
HTTP請求頭 |
trailers |
HTTP請求尾(不常見) |
connection |
當前http連線套接字,為net.Socket的例項 |
socket |
connection屬性的別名 |
client |
client屬性的別名 |
HTTP請求一般可以分為兩部分:請求頭和請求體,以上內容由於長度較短都可以在請求頭解析完成後立即讀取,而請求體可能相對較長,需要一定的時間傳輸,因此http.ServerRequest提供了以下3個事件用於控制請求體傳輸。
data:當請求體資料到來時,該事件觸發。該事件提供一個引數chunk,表示接收到的資料,如果該事件沒有被監聽,那麼請求體將被拋棄。該事件可能會被呼叫多次。
end:當請求體資料傳輸完成時,該事件被觸發,此後將不會再有資料到來。
close:使用者當前請求結束時,該事件觸發。不同於end,如果使用者強制終止了傳輸,也還是呼叫close。
3獲取GET請求內容
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/html’});
res.end(util.inspect(url.parse(req.url,true)));
}).listen(3000);
parse後返回的物件包含
{
search:’?name=aaa&key=…’,
query:{name:’aaa’,key:’’}
pathname:’問號前的如/user’
path:’’,
href:’’
}
4 獲取POST請求內容
HTTP協議1.1版本提供了8種標準的請求方法,其中最常見的就是GET和POST。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 = questring.parse(post);
res.end(util.inspect(post));
});
}).listen(3000);
上面程式碼並沒有在請求響應函式中向客戶端返回資訊。
通過querystring.parse將post解析為真正的POST請求格式
5.http.ServerResponse
http.ServerResponse是返回給客戶端的資訊,決定了使用者最終能看到的結果。它也是由http.Server的request事件傳送的,作為第二個引數傳遞,一般簡稱為response或res。
httpServerResponse有三個重要的成員函式,用於返回響應頭、響應內容以及結束請求。
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]):結束響應,告知客戶端所有傳送已經完成。當所有返回的內容傳送完畢的時候,該函式必須被呼叫一次。如果不呼叫該函式,客戶端將永遠處於等待狀態。
HTTP客戶端
http模組提供了兩個函式http.request和http.get,功能是作為客戶端向HTTP伺服器發起請求。
http.request(options,callback)發起HTTP請求,接受兩個引數,option是一個類似關聯陣列的物件,表示請求的引數,callback是請求的回撥函式。option常用引數如下:
l host:請求網站的域名或IP地址。
l port:請求網站的埠,預設80。
l method:請求方法,預設是GET
l path:請求相對根的路徑,預設是“/”QueryString應該包含在其中。
l headers:一個關聯陣列物件,為請求頭的內容
callback傳遞一個引數,為http.ClientResponse的例項
http.request返回一個http.ClientRequest的例項。如下通過http.request傳送POST請求程式碼:
//httprequest.js
var http =require(‘http’);
var querystring =require(‘querystring’);
var contents =querystring.stringify({
name:’will’,
email:’[email protected]’,
adress:’fsfsdfsdfs’;
});
var options = {
host:’www.byvoid.com’,
path:’/application/node/post.php’,
method:’POST’,
headers:{
‘Content-Type’:’application/x-www.form-urlencoded’,
‘Content-Length:contents.length,
}
};
var req =http.request(options,function(res){
res.setEncoding(‘utf-8’);
res.on(‘data’,function(data){
console.log(data);
});
});
req.write(contents);
req.end();
http.get(options,callback) http模組還提供了一個更加簡便的方法便於處理GET請求:http.get。它是http.request的簡化版,唯一區別在於http.get自動將請求方法裝置成GET請求,同時不需要手動呼叫req.end();
httpget.js
var http =require(‘http’);
http.get({host:’www.baidu.com’},function(res){
res.setEncoding(‘utf8’);
res.on(‘data’,function(data){
console.log(data);
});
});
http.ClientRequest
http.ClientRequest是由http.request或http.get返回產生物件,表示一個已經產生而且正在進行中的HTTP請求。它提供一個response事件,即http.request或http.get第二個引數指定的回撥函式的繫結物件。也可以顯式地繫結這個事件的監聽函式
//httpresponse.js
var http =require(‘http’);
var req =http.get({host:’www.baidu.com’});
req.on(“response”,function(res){
res.setEncoding(‘utf8’);
res.on(‘data’,function(data){
console.log(data);
}
})
http.ClientRequest像http.ServerResponse一樣也提供了write和end函式,用於向伺服器傳送請求體,通常用於POST、PUT等操作。所有寫結束以後必須呼叫end函式以通知伺服器,否則請求無效。
它還提供以下函式:
request.abort():終止正在傳送的請求
request.setTimeout(timeout,[callback])設定請求超時時間,
request.setNoDelay([noDelay])
request.setSocketKeepAlive([enable],[initialDelay])等函式
http.ClientResponse
http.ClientResponse與http.ServerRequest相似,提供三個事件data,end,和close,分別在資料到達、傳輸結束和連線結束時觸發,其中data事件傳遞一個引數chunk,表示接收到資料。
http.ClientResponse也提供了一些屬性,用於表示請求的結果狀態,
名稱 |
含義 |
statusCode |
200/404 |
httpVersion |
協議版本 |
headers |
http請求頭 |
trailers |
http請求尾 |
還提供以下特殊函式:
response.setEncoding([encoding]);當data事件被觸發時,資料將會以encoding編碼。預設值為null,即不編碼,以Buffer形式儲存。常用utf8
response.pause():暫停接收資料和傳送事件,方便實現下載功能
response.resume():從暫停狀態中恢復。