本文轉自 http://my.oschina.net/antianlu/blog/228511
摘要
翻譯和注釋了http 模塊嘹害,講述輸入使用,在什么地方寫代碼
對于初學者有沒有發(fā)覺在查看Node.js官方API的時候非常簡單吮便,只有幾個洋文描述兩下子笔呀,沒了,我第一次一口氣看完所以API后髓需,對于第一個示例都有些懵许师,特別是參數(shù)里的request和response,究竟是如何通過參數(shù)工作的僚匆,如果并發(fā)量大如何確保每個人訪問和提交的數(shù)據不干擾等等微渠。都沒有教你具體如何在開發(fā)中使用,如何著手寫代碼咧擂,給你一個Event 'close'逞盆,只說了下在服務器關閉時觸發(fā),完了屋确。如果沒有了解EventEmitter的核心事件纳击,可能還真不知道如何抒寫代碼并在開發(fā)中真正使用续扔。而http server創(chuàng)建的服務對象已經繼承了EventEmitter,所以可以直接使用on進行監(jiān)聽即可焕数。學學util包中的inherits是如何繼承EventEmitter的就應該略知一二了纱昧。
在官方文檔的API中有服務器對象和回調函數(shù)參數(shù)返回參數(shù)的對象,response和request對象各有兩種不同堡赔。一種是server級別的一種是client級別的识脆。
關于HTTP部分大致分為如下的重要點:
直接通過http對象使用的有:
一、http.STATUS_CODES
二善已、http.createServer
三灼捂、http.request(http.ClientRequest)
四、http.get
五换团、http.globalAgent
作為回調參數(shù)使用的對象有:
一、http.STATUS_CODES
眾所周知艘包,http服務器就是一個狀態(tài)服務器的猛,可以根據狀態(tài)碼來確定服務器是處于請求的什么狀態(tài)。如下列出Node.js status code的全部狀態(tài)對于的解釋想虎。
http:?{STATUS_CODES:?{'100':'Continue','101':'Switching?Protocols','102':'Processing','200':'OK','201':'Created','202':'Accepted','203':'Non-Authoritative?Information','204':'No?Content','205':'Reset?Content','206':'Partial?Content','207':'Multi-Status','300':'Multiple?Choices','301':'Moved?Permanently','302':'Moved?Temporarily','303':'See?Other','304':'Not?Modified','305':'Use?Proxy','307':'Temporary?Redirect','400':'Bad?Request','401':'Unauthorized','402':'Payment?Required','403':'Forbidden','404':'Not?Found','405':'Method?Not?Allowed','406':'Not?Acceptable','407':'Proxy?Authentication?Required','408':'Request?Time-out','409':'Conflict','410':'Gone','411':'Length?Required','412':'Precondition?Failed','413':'Request?Entity?Too?Large','414':'Request-URI?Too?Large','415':'Unsupported?Media?Type','416':'Requested?Range?Not?Satisfiable','417':'Expectation?Failed','418':'I\'m?a?teapot','422':'Unprocessable?Entity','423':'Locked','424':'Failed?Dependency','425':'Unordered?Collection','426':'Upgrade?Required','428':'Precondition?Required','429':'Too?Many?Requests','431':'Request?Header?Fields?Too?Large','500':'Internal?Server?Error','501':'Not?Implemented','502':'Bad?Gateway','503':'Service?Unavailable','504':'Gateway?Time-out','505':'HTTP?Version?Not?Supported','506':'Variant?Also?Negotiates','507':'Insufficient?Storage','509':'Bandwidth?Limit?Exceeded','510':'Not?Extended','511':'Network?Authentication?Required'}}
測試用例:
varhttp?=require('http');http.createServer(function(req,res){varstatus?=?req.url.substr(1);if(?!?http.STATUS_CODES[status])????{????????status?='404';????}????res.writeHeader(status,{'Content-Type':'text/plain'});????res.end(http.STATUS_CODES[status]);}).listen(3000);
測試連接:http://localhost:3000/500結果輸出Internal?Server?Error
二卦尊、http.createServer
http.createServer是創(chuàng)建一臺web服務器的關鍵所在,是處理請求和回應的主函數(shù)出口和出口舌厨,我們把http.createServer創(chuàng)建的服務對象定義為server.代碼如下岂却。
/**
*?Created?by?Administrator?on?14-4-29.
*/varhttp?=require('http');/**
*?創(chuàng)建服務器的兩種寫法,第一種寫法如下
*?由于server已經繼承了EventEmitter的事件功能裙椭,所以可以使用高級函數(shù)編寫方式監(jiān)控事件
*@param{Function}?request?event
*/varserver?=?http.createServer(function(req,res){//這里的req為http.serverRequestres.writeHeader(200,{'Content-Type':'text/plain'});????res.end('hello?world');});/**
*?說明:創(chuàng)建服務器的第二種寫法
*?有關server對象的事件監(jiān)聽
*@param{Object}?req?是http.IncomingMessag的一個實例躏哩,在keep-alive連接中支持多個請求
*@param{Object}?res?是http.ServerResponse的一個實例
*/varserver?=newhttp.Server();server.on('request',function(req,res){????res.writeHeader(200,{'Content-Type':'text/plain'});????res.end('hello?world');});/**
*?說明:新的TCP流建立時出發(fā)。?socket是一個net.Socket對象骇陈。?通常用戶無需處理該事件震庭。
*?特別注意,協(xié)議解析器綁定套接字時采用的方式使套接字不會出發(fā)readable事件你雌。?還可以通過request.connection訪問socket器联。
*@param{Object}?socket
*/server.on('connection',function(socket){});/**
*?源API:?Event:?'close'
*?說明:關閉服務器時觸發(fā)
*/server.on('close',function(){});/**
*?說明:每當收到Expect:?100-continue的http請求時觸發(fā)。?如果未監(jiān)聽該事件婿崭,服務器會酌情自動發(fā)送100?Continue響應拨拓。
*?處理該事件時,如果客戶端可以繼續(xù)發(fā)送請求主體則調用response.writeContinue氓栈,?如果不能則生成合適的HTTP響應(例如渣磷,400?請求無效)
*?需要注意到,?當這個事件觸發(fā)并且被處理后,?request?事件將不再會觸發(fā).
*@param{Object}?req
*@param{Object}?req
*/server.on('checkContinue',function(req,res){});/**
*?說明:如果客戶端發(fā)起connect請求,如果服務器端沒有監(jiān)聽授瘦,那么于客戶端請求的該連接將會被關閉
*@param{Object}?req?是該HTTP請求的參數(shù)醋界,與request事件中的相同竟宋。
*@param{Object}?socket?是服務端與客戶端之間的網絡套接字。需要自己寫一個data事件監(jiān)聽數(shù)據流
*@param{Object}?head?是一個Buffer實例形纺,隧道流的第一個包丘侠,該參數(shù)可能為空。
*/server.on('connect',function(req,socket,head){});/**
*?說明:這個事件主要是對HTTP協(xié)議升級為其他協(xié)議后的事件監(jiān)聽逐样,如果服務器端沒有監(jiān)聽蜗字,那么于客戶端請求的該連接將會被關閉
*@param{Object}?req?是該HTTP請求的參數(shù),與request事件中的相同脂新。
*@param{Object}?socket?是服務端與客戶端之間的網絡套接字挪捕。需要自己寫一個data事件監(jiān)聽數(shù)據流
*@param{Object}?head?是一個Buffer實例,升級后流的第一個包争便,該參數(shù)可能為空级零。
*/server.on('upgrade',function(req,socket,head){});/**
*?說明:如果一個客戶端連接觸發(fā)了一個?'error'?事件,?它就會轉發(fā)到這里
*@param{Object}?exception
*@param{Object}?socket
*/server.on('clientError',function(exception,socket){});/**
*?源API:server.listen(port,?[hostname],?[backlog],?[callback])
*?說明:監(jiān)聽一個?unix?socket,?需要提供一個文件名而不是端口號和主機名。
*@param{Number}?port?端口
*@param{String}?host?主機
*@param{Number}?backlog?等待隊列的最大長度滞乙,決定于操作系統(tǒng)平臺妄讯,默認是511
*@param{Function}?callback?異步回調函數(shù)
*///server.listen(3000,'localhost',100,function(){});/**
*?源API:server.listen(path,?[callback])
*?說明:啟動一個?UNIX?套接字服務器在所給路徑?path?上監(jiān)聽連接。
*?可能用處:多路徑或渠道數(shù)據來源監(jiān)聽分隔
*@param{String}?path
*@param{Function}?callback
*///server.listen('path',function(){})/**
*?源API:server.listen(handle,?[callback])
*?說明:Windows?不支持監(jiān)聽一個文件描述符酷宵。
*@param{Object}?handle?變量可以被設置為server?或者?socket
*@param{Function}?callback
*///server.listen({},function(){});/**
*?說明:最大請求頭數(shù)目限制,?默認?1000?個.?如果設置為0,?則代表不做任何限制.
*@type{number}
*/server.maxHeadersCount?=1000;/**
*?源API:server.setTimeout(msecs,?callback)
*?說明:為套接字設定超時值。如果一個超時發(fā)生躬窜,那么Server對象上會分發(fā)一個'timeout'事件浇垦,同時將套接字作為參數(shù)傳遞。
*?設置為0將阻止之后建立的連接的一切自動超時行為
*@param{Number}?msecs
*@param*/server.setTimeout(1000,function(){});/**
*?說明:一個套接字被判斷為超時之前的閑置毫秒數(shù)荣挨。?默認?120000?(2?分鐘)
*@type{number}
*/server.timeout?=120000;/**
*?說明:這里的主機將是本地
*@param{Number}?port?端口
*@param{Function}?callback?異步回調函數(shù)
*/server.listen(3000,function(){???console.log('Listen?port?3000');});
三 男韧、http.request
http 模塊提供了兩個函數(shù) http.request 和 http.get,功能是作為客戶端向 HTTP服務器發(fā)起請求默垄。http.request(options, callback) 發(fā)起 HTTP 請求此虑。接受兩個參數(shù),option 是一個類似關聯(lián)數(shù)組的對象口锭,表示請求的參數(shù)朦前,callback 是請求的回調函數(shù)。option常用的參數(shù)如下所示鹃操。http.request 返回一個 http.ClientRequest 的實例韭寸。
/**?*?Created?by?Administrator?on14-4-30.*/var?http?=require('http');var?server?=?http.createServer(function(req,res){}).listen(3000);/**?*?參數(shù)配置?*?@type{{hostname:string,?port:?number,?method:string,?path:string,handers:?{}}}?*?host:請求的服務器域名或者IP地址?*?port:端口?*?method:請求方式有POST,GET,INPUT,DELETE,CONNECT,默認為GET?*?path:請求地址荆隘,可包含查詢字符串以及可能存在的錨點恩伺。例如'/index.html?page=12'*?handers:?一個包含請求頭的對象。?*/var?options?={????hostname?:'www.google.com',????port?:80,????method?:'POST',????path?:'/upload',????handers:{}};/**?*?如下特別的消息頭應當注意:?*?發(fā)送'Connection:?keep-alive'頭部將通知Node此連接將保持到下一次請求椰拒。?*?發(fā)送'Content-length'頭將使默認的分塊編碼無效晶渠。?*?發(fā)送'Expect'頭部將引起請求頭部立即被發(fā)送凰荚。?*?通常情況,當發(fā)送'Expect:?100-continue'時褒脯,你需要監(jiān)聽continue事件的同時設置超時便瑟。參見RFC26168.2.3章節(jié)以獲得更多的信息。?*//**?*?說明:官方給出的例子?*?應用場景:模擬客服端請求服務器,是一個HTTP?客戶端工具臼节,用于向?HTTP?服務器發(fā)起請求鸭你。?*?@param?{Object}?options?*?@param?{Function}?callback?*/var?req?=?http.request(options,function(res){????console.log(res);????console.log('STATUS:'+?res.statusCode);????console.log('HEADERS:'+?JSON.stringify(res.headers));????res.setEncoding('utf8');????res.on('data',function(chunk){???????console.log('BODY'+?chunk);????});});req.on('response',function(){});req.on('connect',function(){});req.on('socket',function(){});req.on('upgrade',function(){});req.on('continue',function(){})//如果在請求過程中出現(xiàn)了錯誤(可能是DNS解析、TCP的錯誤养盗、或者HTTP解析錯誤),返回的請求對象上的'error'的事件將被觸發(fā)适篙。req.on('error',function(e){???console.log(e.message);});/**?*?源API:request.write(chunk,?[encoding])?*?說明:發(fā)送正文中的一塊往核。用戶可以通過多次調用這個方法將請求正文以流的方式發(fā)送到服務器。此種情況建議在建立請求時使用['Transfer-Encoding','chunked']請求頭嚷节。?*?@param?{ObjectorString}?chunk?參數(shù)chunk應當是一個整數(shù)數(shù)組或字符串聂儒。?*?@param?{String}?encoding?參數(shù)encoding是可選的,僅在chunk為字符串時可用硫痰。?*/req.write('data\n');/**?*?源API:request.end(chunk,?[encoding])?*?說明:完成本次請求的發(fā)送衩婚。如果正文中的任何一個部分沒有來得及發(fā)送,將把他們全部刷新到流中效斑。如果本次請求是分塊的非春,這個函數(shù)將發(fā)出結束字符'0\r\n\r\n'。如果使用參數(shù)data缓屠,就等于在調用request.write(data,?encoding)之后緊接著調用request.end()奇昙。?*?@param?{ObjectorString}?chunk?參數(shù)chunk應當是一個整數(shù)數(shù)組或字符串。?*?@param?{String}?encoding?參數(shù)encoding是可選的敌完,僅在chunk為字符串時可用储耐。?*?example:?req.end(),req.end('data\n'),req.end('data','utf8'),req.end(chunk)?*/req.end();/**?*?阻止一個請求。(v0.3.8中新增的方法滨溉。)?*/req.abort();/**?*?源API:request.setTimeout(timeout,?[callback])?*?說明:一旦給這個請求分配的是一個socket時此函數(shù)會被調用?*?@param?{Number}?timeout?毫秒?*?@param?{Function}?callback?回到函數(shù)?*/req.setTimeout(1000,function(){});/**?*?源API?:request.setNoDelay([noDelay])?*?說明:默認有一定的延遲什湘,設置為0表示無延遲?*?@param?{Number}?noDelay?*/req.setNoDelay(0)/**?*?源API:request.setSocketKeepAlive([enable],?[initialDelay])?*?????類似同上?*/
四、http.get
http.get(options,
callback) http 模塊還提供了一個更加簡便的方法用于處理GET請求:http.get业踏。它是 http.request
的簡化版禽炬,唯一的區(qū)別在于http.get自動將請求方法設為了 GET 請求,同時不需要手動調用 req.end()勤家。
/**
*?Created?by?Administrator?on?14-4-30.
*/varhttp?=require('http');http.createServer(function(req,res){}).listen(3000);/**
*?說明:由于大部分請求是不包含正文的GET請求腹尖,Node提供了這個方便的方法。與http.request()唯一的區(qū)別是此方法將請求方式設置為GET,并且自動調用req.end()热幔。
*?應用:服務器端測試客服端請求調試等
*@param{String}?url?有效地址
*@param{Function}?callback
*/http.get('http://www.baidu.com/index.html',function(res){????console.log('get?response?Code?:'+?res.statusCode);}).on('error',function(e){????????console.log("Got?error:?"+?e.message);????})