nodejs中的HTTP服務
nodejs最重要的方面之一是具有非常迅速的實現HTTP和HTTPS服務器和服務的能力。http服務是相當低層次的,你可能要用到不同的模塊,如express來實現完整的Web服務器,http模塊不提供處理路由、cookie、緩存等的調用。我們主要用http模塊的地方是實現供應用程序使用的后端Web服務。
1.處理URL
統一資源定位符(URL)為把一個請求發到正確的服務器的特定端口上,並訪問合適的數據提供了所有需要的信息。一個URL可以被分解成幾個不同的組成部分,每個部分都為Web服務器如何路由和處理來自客戶端的HTTP請求提供一塊基本的信息。node提供了url模塊,提供了把一個URL字符串轉換成一個URL對象的功能。
要從一個URL字符串創建URL對象,把URL字符串作為第一個參數下面的方法:
url.parse(urlStr,[parseQueryString],[slashesDenoteHost)
其中,parseQueryString參數是一個布爾值,如果為true,那么也把URL的查詢字符串部分解析為對象字面量,默認值為false。
slashesDenoteHost參數也是一個布爾值,如果為true,那么就會把格式為//host/path的URL解析為{host:'host',pathname:'/path'},而不是{pathname:'//host/path'}
還可以用url.format(urlObj)方法將一個URL對象轉換成字符串的形式。
由url.parse()創建出來的URL對象的屬性:
path 完整路徑,包括路徑和搜索
query 要么是查詢字符串中的參數部分,要么是含有查詢字符串參數和值的解析后的對象。如果parseQueryString設置為true,那么就是解析后的對象
search URL的查詢字符串部分,包括前導的問號
pathname URL的路徑部分(包括最初的斜線,如果存在的話)
port 主機的端口號
hostname 主機的主機名,小寫
auth URL的身份認證信息
host URL的完整主機部分,包括端口信息,小寫
protocol 請求協議
href 這是最初解析的完整的URL字符串
hash URL的散列部分,包括井號
2.解析URL組件
url模塊有用的一種功能就是用與瀏覽器相同的方式來解析URL的組件,這可以讓你在服務器端操作URL字符串,以在URL中作出調整。
把一個URL解析到新的位置:
url.resolve(from,to)
其中,from指定了原始基礎URL字符串,to指定了想要URL被解析到的新位置。
舉個例子:
var url=require('url'); var originalUrl='http://user:pass@host:80/resource/path?query=string#hash'; var newResource='/another/path?querynew'; console.log(url.resolve(originalUrl,newResource));
3.處理查詢字符串和表單參數
HTTP請求通常在URL中包含查詢字符串(由URL對象獲得)或在正文內包含參數數據來處理表單的提交(從客戶端請求的正文讀出)。查詢字符串和表單參數都只是基本的鍵值對,需要使用querystring模塊的parse()方法將字符串轉換成JavaScript對象:
querystring.parse(str,[sep],[eq],[options])
str是查詢或參數字符串,sep參數允許你指定使用的分隔符,默認的分隔符是&,eq參數允許你指定分析時使用的賦值運算符,默認值為=,options參數是一個具有屬性maxKeys的對象,它能夠讓你限制生成的對象可以包含的鍵的數量,默認是1000。
var qstring=require('querystring'); var params=qstring.parse('name=Braad&color=red&color=blue'); console.log(params);
4.請求、響應和服務器對象
(1) http.ClientRequest對象
當你構建一個HTTP客戶端時,調用http.request()使得一個ClientRequest對象在內部被創建,這個對象是為了當該請求在服務器上進展的時候來表示它。通常使用ClientRequest對象來啟動、監控和處理來自服務器的響應。
實現ClientRequest對象:
http.request(options,callback)
其中,options參數是一個對象,其屬性定義了如何把客戶端的HTTP請求打開並發送到服務器,包括host,path,method,port等屬性。callback是一個回調函數,在把請求發送到服務器后,處理從服務器返回的響應時調用此回調函數,此回調函數唯一的參數是一個IncomingMessage對象,該對象是來自服務器的響應。
一個ClientRequest對象的基本實現:
var http=require('http'); var options={ hostname:'www.myserver.com', path:'/', port:'8080', method:'POST' }; var req=http.request(options,function(response){ var str=''; response.on('data',function(chunk){ str+=chunk; }); response.on('end',function(){ console.log(str); }); }); req.end();
ClientRequest對象的方法:
write(chunk,[encoding]) 把一個正文數據塊(Buffer或String對象)寫入請求
end([data],[encoding]) 把可選的數據寫入請求正文,然后刷新Writeable流並終止該請求
abort() 終止當前的請求
setTimeout(timeout,[callback]) 為請求設置套接字超時時間
setNoDelay([noDelay]) 禁用在發送數據之前緩沖數據的Nagle算法,noDelay是一個布爾值,true表示立即寫,false表示緩沖寫入
setSocketKeepAlive([enable],[initialDelay]) 啟用和禁用對客戶機請求的保持活動功能,enable默認為false,即禁用;initialDelay指定最后一個數據包和第一個保持活動請求之間的延遲
(2)http.ServerResponse對象
當HTTP服務器接收到一個Request事件時,它在內部創建ServerResponse對象,這個對象作為第二個參數被傳遞到request事件處理程序。可以使用ServerResponse對象指定並發送到客戶端的響應。
ServerResponse對象的方法:
writeContinue() 發送一個HTTP/1.1 100 Continue消息給客戶端,請求被發送的正文內容
writeHead(statusCode,[reasonPhrase],[headers]) 把一個響應標頭寫入請求,例如response.writeHead(200,'successs',{'Content-Length':body.length,'Content-Type':'text/plain'});
setTimeout(timeout,[callback]) 設置客戶端連接的套接字超時時間
setHeader(name,value) 設置一個特定的標頭值
getHeader(name) 獲取已在響應中設置的一個HTTP標頭
removeHeader(name) 移除已在響應中設置的一個HTTP標頭
write(chunk,[encoding]) 寫入chunk,Buffer或String對象到響應Writeable流,僅把數據寫入響應的正文部分
addTrailers(headers) 將HTTP尾隨標頭寫入響應的結束處
end([data],[encoding]) 把可選的數據輸出寫入響應的正文,然后刷新Writeable流並響應該請求
(3)http.IncomingMessage對象
HTTP服務器和客戶端都創建IncomingMessage對象,該對象實現了Readable流,讓你能夠把客戶端請求或服務器響應作為流院讀入,這意味着它們的readable和data事件可以被監聽並用來從流中讀出數據。
IncomingMessage對象中可用的事件、屬性和方法
close 當底層套接字被關閉時發出
httpVersion 指定用於構建客戶端請求/響應的HTTP版本
headers 包含了隨請求/響應發送的標頭的一個對象
method 指定用於請求/響應的方法
url 發送到服務器的URL字符串
statusCode 指定來自服務器的3位數狀態碼
socket 一個指向net.Socket對象的句柄,用來與客戶端/服務器的通信
setTimeout(timeout,[callback]) 設置連接的套接字超時時間
(4)HTTP Server對象
HTTP Server對象提供了實現HTTP服務器的基本框架,它提供了一個監聽端口的底層套接字和接收請求,然后發送響應給客戶端連接的處理程序,當服務器正在監聽時,node應用程序並沒有結束。
要啟動HTTP服務器,首先需要createServer()方法創建一個Server對象:
http.createServer([requestListener])
此方法返回Server對象,requestListener參數是在請求事件被觸發時執行的回調函數,此回調函數接收兩個參數,一個是代表客戶端請求的IncomingMessage對象,第二個參數是用來指定和發送響應的ServerResponse對象。
創建了server對象,就可以在server對象上的listen()方法開始監聽它:
listen(port,[hostname],[backlog],[callback])
一個基本的例子:
var http=require('http'); http.createServer(function(req,res){ //handle resquest and response }).listen(8080);
實現一個基本的靜態文件服務
//實現一個靜態文件服務器 var fs=require('fs'); var http=require('http'); var url=require('url'); //創建一個服務器 http.createServer(function(req,res){ if(req.url!="/favicon.ico"){ var urlObj=url.parse(req.url,true,false); console.log(urlObj.pathname); fs.readFile('.'+urlObj.pathname+'.html',function(err,data){ if(err){ res.writeHead(404); res.end(JSON.stringify(err)); return; } console.log(data.toString()); //將文件的內容寫入res響應對象 res.end(data); }); } }).listen(8080); //實現一個HTTP客戶端,向服務器發送一個GET請求來檢索文件內容 var options={ hostname:'127.0.0.1', port:'8080', path:'/aaa' }; //on('data')讀取來自服務器的響應中的內容,on('end')把文件內容記錄到到一個文件 function handleResponse(response){ var serverData=''; response.on('data',function(chunk){ serverData+=chunk; }); response.on('end',function(){ console.log(serverData); }); } http.request(options,function(response){ handleResponse(response); }).end();
實現動態的GET服務器
var http=require('http'); var messages=[ 'message1', 'message2', 'message3' ]; http.createServer(function(req,res){ res.setHeader('Content-Type','text/html'); res.writeHead(200); res.write('<html><head><title>HTTP Server</title></head>'); res.write('<body>'); for(var idx in messages){ res.write('\n<h1>'+messages[idx]+'</h1>'); } res.end('\n</body></html>'); }).listen(8080); var options={ hostname:'localhost', port:'8080' }; function handleResponse(response){ var serverData=''; response.on('data',function(chunk){ serverData+=chunk; }); response.on('end',function(){ console.log('response status: ',response.statusCode); console.log('response headers: ',response.headers); console.log(serverData); }); } http.request(options,function(response){ handleResponse(response); }).end();
