咱們知道傳統的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
文章開頭使用的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是一個基於事件的服務器,她是繼承自EventEmitter,事實上,nodejs中大部分模塊都繼承自EventEmitter,包括fs、net等模塊,這也是爲何說nodejs基於事件驅動(關於EventEmitter的更多內容能夠在官方api下的events模塊找到),http.Server提供的事件以下:jquery
正如上面咱們所看到的request事件是最經常使用的,而參數req和res分別是http.IncomingMessage和http.ServerResponse的實例,那麼咱們來看看這兩個類吧json
http.IncomingMessage是HTTP請求的信息,是後端開發者最關注的內容,通常由http.Server的request事件發送,並做爲第一個參數傳遞,http請求通常能夠分爲兩部分:請求頭和請求體(更多關於http協議的知識能夠查看我以前的筆記http入門與挖坑);其提供了3個事件,以下後端
http.IncomingMessage的屬性以下:api
http.ServerResponse是返回給客戶端的信息,決定了用戶最終看到的內容,通常也由http.Server的request事件發送,並做爲第二個參數傳遞,它有三個重要的成員函數,用於返回響應頭、響應內容以及結束請求數組
看完http服務器,咱們看一看http的客戶端吧瀏覽器
http模塊提供了兩個函數http.request和http.get,功能是做爲客戶端向http服務器發起請求。
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.request方法的簡化版,惟一的區別是http.get自動將請求方法設爲了GET請求,同時不須要手動調用req.end(),可是須要記住的是,若是咱們使用http.request方法時沒有調用end方法,服務器將不會收到信息。由於http.get和http.request方法都是放回一個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.ServerRequest類似,提供了三個事件,data、end、close,分別在數據到達、傳輸結束和鏈接結束時觸發,其中data事件傳遞一個參數chunk,表示接受到的數據。其屬性以下
此外,這個對象提供了幾個特殊的函數
好的,到這裏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代碼,這個模塊的介紹就到這裏了(你們不要用這個模塊的知識去幹壞事哦,不然我可不負責┑( ̄Д  ̄)┍)。