淺析nodejs的http模塊

咱們知道傳統的HTPP服務器會由Aphche、Nginx、IIS之類的軟件來擔任,可是nodejs並不須要,nodejs提供了http模塊,自身就能夠用來構建服務器,並且http模塊是由C++實現的,性能可靠。咱們在nodejs中的教程或者書籍中經常會經過一個簡易的http服務器來做爲開頭的學習,就像下面這個例子javascript

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

打開瀏覽器,輸入localhost:3000咱們就能夠看到屏幕上的hello nodejs了,這代表這個最簡單的nodejs服務器已經搭建成功了。
nodejs中的http模塊中封裝了一個HTPP服務器和一個簡易的HTTP客戶端,http.Server是一個基於事件的http服務器,http.request則是一個http客戶端工具,用於向http服務器發起請求。而上面的createServer方法中的參數函數中的兩個參數req和res則是分別表明了請求對象和響應對象。其中req是http.IncomingMessage的實例,res是http.ServerResponse的實例,這能夠從nodejs中的源碼中獲取這個信息(固然咱們做爲初學者,天然是不太可能讀懂其源碼,推薦慕課網的課程《進擊的nodjs基礎(一)》,scott老師會帶咱們基本走一下http模塊的源碼,會有一個大概的瞭解)。如下將從http服務器和http客戶端簡要走一遍http模塊html

1、http服務器####


文章開頭使用的createServer方法返回了一個http.Server對象,這實際上是一個建立http服務的捷徑,若是咱們用如下代碼來實現的話,也將同樣可行java

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的事件吧node

 

 

一、http.Server的事件######

正如咱們上面所說,http.Server是一個基於事件的服務器,她是繼承自EventEmitter,事實上,nodejs中大部分模塊都繼承自EventEmitter,包括fs、net等模塊,這也是爲何說nodejs基於事件驅動(關於EventEmitter的更多內容能夠在官方api下的events模塊找到),http.Server提供的事件以下:jquery

  • request:當客戶端請求到來時,該事件被觸發,提供兩個參數req和res,表示請求和響應信息,是最經常使用的事件
  • connection:當TCP鏈接創建時,該事件被觸發,提供一個參數socket,是net.Socket的實例
  • close:當服務器關閉時,觸發事件(注意不是在用戶斷開鏈接時)

正如上面咱們所看到的request事件是最經常使用的,而參數req和res分別是http.IncomingMessage和http.ServerResponse的實例,那麼咱們來看看這兩個類吧json

二、http.IncomingMessage######

http.IncomingMessage是HTTP請求的信息,是後端開發者最關注的內容,通常由http.Server的request事件發送,並做爲第一個參數傳遞,http請求通常能夠分爲兩部分:請求頭和請求體(更多關於http協議的知識能夠查看我以前的筆記http入門與挖坑);其提供了3個事件,以下後端

  • data:當請求體數據到來時,該事件被觸發,該事件提供一個參數chunk,表示接受的數據,若是該事件沒有被監聽,則請求體會被拋棄,該事件可能會被調用屢次(這與nodejs是異步的有關係)
  • end:當請求體數據傳輸完畢時,該事件會被觸發,此後不會再有數據
  • close:用戶當前請求結束時,該事件被觸發,不一樣於end,若是用戶強制終止了傳輸,也是用close

http.IncomingMessage的屬性以下:api

 
 
三、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的客戶端吧瀏覽器

2、http客戶端####


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

一、http.request(options,callback)######

options是一個相似關聯數組的對象,表示請求的參數,callback做爲回調函數,須要傳遞一個參數,爲http.ClientResponse的實例,http.request返回一個http.ClientRequest的實例。

options經常使用的參數有host、port(默認爲80)、method(默認爲GET)、path(請求的相對於根的路徑,默認是「/」,其中querystring應該包含在其中,例如/search?query=byvoid)、headers(請求頭內容)

以下示例代碼:

var http=require("http"); var options={ hostname:"cn.bing.com", 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(); 

咱們運行這段代碼咱們在控制檯能夠發現,必應首頁的html代碼已經呈現出來了。

接下來咱們來作一個關於POST請求的代碼。

var http=require("http"); var querystring=require("querystring"); var postData=querystring.stringify({ "content":"我真的只是測試一下", "mid":8837 }); var options={ hostname:"www.imooc.com", port:80, path:"/course/document", method:"POST", headers:{ "Accept":"application/json, text/javascript, */*; q=0.01", "Accept-Encoding":"gzip, deflate", "Accept-Language":"zh-CN,zh;q=0.8", "Connection":"keep-alive", "Content-Length":postData.length, "Content-Type":"application/x-www-form-urlencoded; charset=UTF-8", "Cookie":"imooc_uuid=6cc9e8d5-424a-4861-9f7d-9cbcfbe4c6ae; imooc_isnew_ct=1460873157; loginstate=1; apsid=IzZDJiMGU0OTMyNTE0ZGFhZDAzZDNhZTAyZDg2ZmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjkyOTk0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGNmNmFhMmVhMTYwNzRmMjczNjdmZWUyNDg1ZTZkMGM1BwhXVwcIV1c%3DMD; PHPSESSID=thh4bfrl1t7qre9tr56m32tbv0; Hm_lvt_f0cfcccd7b1393990c78efdeebff3968=1467635471,1467653719,1467654690,1467654957; Hm_lpvt_f0cfcccd7b1393990c78efdeebff3968=1467655022; imooc_isnew=2; cvde=577a9e57ce250-34", "Host":"www.imooc.com", "Origin":"http://www.imooc.com", "Referer":"http://www.imooc.com/video/8837", "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2763.0 Safari/537.36", "X-Requested-With":"XMLHttpRequest", } } var req=http.request(options,function(res){ res.on("data",function(chunk){ console.log(chunk); }); res.on("end",function(){ console.log("評論完畢!"); }); console.log(res.statusCode); }); req.on("error",function(err){ console.log(err.message); }) req.write(postData); req.end(); 

這段代碼咱們模擬了嚮慕課網發起評論的功能,可是由於慕課網對於這種發起方式專門作了重定向,因此咱們並不能在評論區看到咱們的評論(另外在一些對這種請求沒有作處理的網站,擅自發起評論,極可能會當作網絡攻擊,因此不要玩火,你懂得),可是這段代碼卻很能夠說明這個過程。另外,代碼中的請求頭和postData裏面的鍵咱們都是能夠經過開發者工具network下找到的。

二、http.get(options,callback)######

這個方法是http.request方法的簡化版,惟一的區別是http.get自動將請求方法設爲了GET請求,同時不須要手動調用req.end(),可是須要記住的是,若是咱們使用http.request方法時沒有調用end方法,服務器將不會收到信息。由於http.get和http.request方法都是放回一個http.ClientRequest對象,因此咱們來看一下這兩個對象。

三、http.ClientRequest######

http.ClientRequest是由http.request或者是http.get返回產生的對象,表示一個已經產生並且正在進行中的HTPP請求,提供一個response事件,也就是咱們使用http.get和http.request方法中的回調函數所綁定的對象,咱們能夠顯式地綁定這個事件的監聽函數

var http=require("http"); var options={ hostname:"cn.bing.com", port:80 } var req=http.request(options); req.on("response",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(); 

http.ClientRequest也提供了write和end函數,用於向服務器發送請求體,一般用於POST、PUT等操做,全部寫操做都必須調用end函數來通知服務器,不然請求無效。此外,這個對象還提供了abort()、setTimeout()等方法,具體能夠參考文檔

四、http.ClientReponse######

與http.ServerRequest類似,提供了三個事件,data、end、close,分別在數據到達、傳輸結束和鏈接結束時觸發,其中data事件傳遞一個參數chunk,表示接受到的數據。其屬性以下

 
 

此外,這個對象提供了幾個特殊的函數

  • response。setEncoding([encoding]):設置默認的編碼,當data事件被觸發時,數據將會以encoding編碼,默認值是null,也就是不編碼,以buffer形式存儲
  • response.pause():暫停結束數據和發送事件,方便實現下載功能
  • response.resume():從暫停的狀態中恢復

好的,到這裏http模塊的主要功能已經介紹完了。咱們接着來作一個練習,咱們知道中山大學今年院系改革,弄得我這個中大學生也不知道中大到底有那些學院了,是的,咱們打開官網咱們會發現有哪些學院,可是我想用http模塊把裏面的學院名給扒下來,好的,那我就作了如下代碼

var cheerio=require("cheerio"); var http=require("http"); var fs=require("fs"); var options="http://www.sysu.edu.cn/2012/cn/jgsz/yx/index.htm"; var htmlData="" var req=http.request(options,function(res){ res.on("data",function(chunk){ htmlData+=chunk; }); res.on("end",function(){ var $=cheerio.load(htmlData); var textcontent=$("tr").text(); fs.writeFile("./school.txt",textcontent,"utf-8") }); }); req.end(); 

以後咱們就可在school.txt文件中看到全部的學院了,怎麼樣,是否是頗有成就感,題外話,我這裏用了一個外部的模塊cheerio,這個模塊可讓咱們像jquery同樣操做html代碼,這個模塊的介紹就到這裏了(你們不要用這個模塊的知識去幹壞事哦,不然我可不負責┑( ̄Д  ̄)┍)。

做者:忽如寄 連接:https://www.jianshu.com/p/ab2741f78858 來源:簡書
相關文章
相關標籤/搜索