本文轉(zhuǎn)自 http://my.oschina.net/antianlu/blog/228511
摘要
翻譯和注釋了http 模塊,講述輸入使用,在什么地方寫代碼
對于初學(xué)者有沒有發(fā)覺在查看Node.js官方API的時(shí)候非常簡單,只有幾個(gè)洋文描述兩下子,沒了,我第一次一口氣看完所以API后,對于第一個(gè)示例都有些懵,特別是參數(shù)里的request和response,究竟是如何通過參數(shù)工作的,如果并發(fā)量大如何確保每個(gè)人訪問和提交的數(shù)據(jù)不干擾等等。都沒有教你具體如何在開發(fā)中使用,如何著手寫代碼,給你一個(gè)Event 'close',只說了下在服務(wù)器關(guān)閉時(shí)觸發(fā),完了。如果沒有了解EventEmitter的核心事件,可能還真不知道如何抒寫代碼并在開發(fā)中真正使用。而http server創(chuàng)建的服務(wù)對象已經(jīng)繼承了EventEmitter,所以可以直接使用on進(jìn)行監(jiān)聽即可。學(xué)學(xué)util包中的inherits是如何繼承EventEmitter的就應(yīng)該略知一二了。
在官方文檔的API中有服務(wù)器對象和回調(diào)函數(shù)參數(shù)返回參數(shù)的對象,response和request對象各有兩種不同。一種是server級(jí)別的一種是client級(jí)別的。
關(guān)于HTTP部分大致分為如下的重要點(diǎn):
直接通過http對象使用的有:
一、http.STATUS_CODES
二、http.createServer
三、http.request(http.ClientRequest)
四、http.get
五、http.globalAgent
作為回調(diào)參數(shù)使用的對象有:
一、http.STATUS_CODES
眾所周知,http服務(wù)器就是一個(gè)狀態(tài)服務(wù)器,可以根據(jù)狀態(tài)碼來確定服務(wù)器是處于請求的什么狀態(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結(jié)果輸出Internal?Server?Error
二、http.createServer
http.createServer是創(chuàng)建一臺(tái)web服務(wù)器的關(guān)鍵所在,是處理請求和回應(yīng)的主函數(shù)出口和出口,我們把http.createServer創(chuàng)建的服務(wù)對象定義為server.代碼如下。
/**
*?Created?by?Administrator?on?14-4-29.
*/varhttp?=require('http');/**
*?創(chuàng)建服務(wù)器的兩種寫法,第一種寫法如下
*?由于server已經(jīng)繼承了EventEmitter的事件功能,所以可以使用高級(jí)函數(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)建服務(wù)器的第二種寫法
*?有關(guān)server對象的事件監(jiān)聽
*@param{Object}?req?是http.IncomingMessag的一個(gè)實(shí)例,在keep-alive連接中支持多個(gè)請求
*@param{Object}?res?是http.ServerResponse的一個(gè)實(shí)例
*/varserver?=newhttp.Server();server.on('request',function(req,res){????res.writeHeader(200,{'Content-Type':'text/plain'});????res.end('hello?world');});/**
*?說明:新的TCP流建立時(shí)出發(fā)。?socket是一個(gè)net.Socket對象。?通常用戶無需處理該事件。
*?特別注意,協(xié)議解析器綁定套接字時(shí)采用的方式使套接字不會(huì)出發(fā)readable事件。?還可以通過request.connection訪問socket。
*@param{Object}?socket
*/server.on('connection',function(socket){});/**
*?源API:?Event:?'close'
*?說明:關(guān)閉服務(wù)器時(shí)觸發(fā)
*/server.on('close',function(){});/**
*?說明:每當(dāng)收到Expect:?100-continue的http請求時(shí)觸發(fā)。?如果未監(jiān)聽該事件,服務(wù)器會(huì)酌情自動(dòng)發(fā)送100?Continue響應(yīng)。
*?處理該事件時(shí),如果客戶端可以繼續(xù)發(fā)送請求主體則調(diào)用response.writeContinue,?如果不能則生成合適的HTTP響應(yīng)(例如,400?請求無效)
*?需要注意到,?當(dāng)這個(gè)事件觸發(fā)并且被處理后,?request?事件將不再會(huì)觸發(fā).
*@param{Object}?req
*@param{Object}?req
*/server.on('checkContinue',function(req,res){});/**
*?說明:如果客戶端發(fā)起connect請求,如果服務(wù)器端沒有監(jiān)聽,那么于客戶端請求的該連接將會(huì)被關(guān)閉
*@param{Object}?req?是該HTTP請求的參數(shù),與request事件中的相同。
*@param{Object}?socket?是服務(wù)端與客戶端之間的網(wǎng)絡(luò)套接字。需要自己寫一個(gè)data事件監(jiān)聽數(shù)據(jù)流
*@param{Object}?head?是一個(gè)Buffer實(shí)例,隧道流的第一個(gè)包,該參數(shù)可能為空。
*/server.on('connect',function(req,socket,head){});/**
*?說明:這個(gè)事件主要是對HTTP協(xié)議升級(jí)為其他協(xié)議后的事件監(jiān)聽,如果服務(wù)器端沒有監(jiān)聽,那么于客戶端請求的該連接將會(huì)被關(guān)閉
*@param{Object}?req?是該HTTP請求的參數(shù),與request事件中的相同。
*@param{Object}?socket?是服務(wù)端與客戶端之間的網(wǎng)絡(luò)套接字。需要自己寫一個(gè)data事件監(jiān)聽數(shù)據(jù)流
*@param{Object}?head?是一個(gè)Buffer實(shí)例,升級(jí)后流的第一個(gè)包,該參數(shù)可能為空。
*/server.on('upgrade',function(req,socket,head){});/**
*?說明:如果一個(gè)客戶端連接觸發(fā)了一個(gè)?'error'?事件,?它就會(huì)轉(zhuǎn)發(fā)到這里
*@param{Object}?exception
*@param{Object}?socket
*/server.on('clientError',function(exception,socket){});/**
*?源API:server.listen(port,?[hostname],?[backlog],?[callback])
*?說明:監(jiān)聽一個(gè)?unix?socket,?需要提供一個(gè)文件名而不是端口號(hào)和主機(jī)名。
*@param{Number}?port?端口
*@param{String}?host?主機(jī)
*@param{Number}?backlog?等待隊(duì)列的最大長度,決定于操作系統(tǒng)平臺(tái),默認(rèn)是511
*@param{Function}?callback?異步回調(diào)函數(shù)
*///server.listen(3000,'localhost',100,function(){});/**
*?源API:server.listen(path,?[callback])
*?說明:啟動(dòng)一個(gè)?UNIX?套接字服務(wù)器在所給路徑?path?上監(jiān)聽連接。
*?可能用處:多路徑或渠道數(shù)據(jù)來源監(jiān)聽分隔
*@param{String}?path
*@param{Function}?callback
*///server.listen('path',function(){})/**
*?源API:server.listen(handle,?[callback])
*?說明:Windows?不支持監(jiān)聽一個(gè)文件描述符。
*@param{Object}?handle?變量可以被設(shè)置為server?或者?socket
*@param{Function}?callback
*///server.listen({},function(){});/**
*?說明:最大請求頭數(shù)目限制,?默認(rèn)?1000?個(gè).?如果設(shè)置為0,?則代表不做任何限制.
*@type{number}
*/server.maxHeadersCount?=1000;/**
*?源API:server.setTimeout(msecs,?callback)
*?說明:為套接字設(shè)定超時(shí)值。如果一個(gè)超時(shí)發(fā)生,那么Server對象上會(huì)分發(fā)一個(gè)'timeout'事件,同時(shí)將套接字作為參數(shù)傳遞。
*?設(shè)置為0將阻止之后建立的連接的一切自動(dòng)超時(shí)行為
*@param{Number}?msecs
*@param*/server.setTimeout(1000,function(){});/**
*?說明:一個(gè)套接字被判斷為超時(shí)之前的閑置毫秒數(shù)。?默認(rèn)?120000?(2?分鐘)
*@type{number}
*/server.timeout?=120000;/**
*?說明:這里的主機(jī)將是本地
*@param{Number}?port?端口
*@param{Function}?callback?異步回調(diào)函數(shù)
*/server.listen(3000,function(){???console.log('Listen?port?3000');});
三 、http.request
http 模塊提供了兩個(gè)函數(shù) http.request 和 http.get,功能是作為客戶端向 HTTP服務(wù)器發(fā)起請求。http.request(options, callback) 發(fā)起 HTTP 請求。接受兩個(gè)參數(shù),option 是一個(gè)類似關(guān)聯(lián)數(shù)組的對象,表示請求的參數(shù),callback 是請求的回調(diào)函數(shù)。option常用的參數(shù)如下所示。http.request 返回一個(gè) http.ClientRequest 的實(shí)例。
/**?*?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:請求的服務(wù)器域名或者IP地址?*?port:端口?*?method:請求方式有POST,GET,INPUT,DELETE,CONNECT,默認(rèn)為GET?*?path:請求地址,可包含查詢字符串以及可能存在的錨點(diǎn)。例如'/index.html?page=12'*?handers:?一個(gè)包含請求頭的對象。?*/var?options?={????hostname?:'www.google.com',????port?:80,????method?:'POST',????path?:'/upload',????handers:{}};/**?*?如下特別的消息頭應(yīng)當(dāng)注意:?*?發(fā)送'Connection:?keep-alive'頭部將通知Node此連接將保持到下一次請求。?*?發(fā)送'Content-length'頭將使默認(rèn)的分塊編碼無效。?*?發(fā)送'Expect'頭部將引起請求頭部立即被發(fā)送。?*?通常情況,當(dāng)發(fā)送'Expect:?100-continue'時(shí),你需要監(jiān)聽continue事件的同時(shí)設(shè)置超時(shí)。參見RFC26168.2.3章節(jié)以獲得更多的信息。?*//**?*?說明:官方給出的例子?*?應(yīng)用場景:模擬客服端請求服務(wù)器,是一個(gè)HTTP?客戶端工具,用于向?HTTP?服務(wù)器發(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)了錯(cuò)誤(可能是DNS解析、TCP的錯(cuò)誤、或者HTTP解析錯(cuò)誤),返回的請求對象上的'error'的事件將被觸發(fā)。req.on('error',function(e){???console.log(e.message);});/**?*?源API:request.write(chunk,?[encoding])?*?說明:發(fā)送正文中的一塊。用戶可以通過多次調(diào)用這個(gè)方法將請求正文以流的方式發(fā)送到服務(wù)器。此種情況建議在建立請求時(shí)使用['Transfer-Encoding','chunked']請求頭。?*?@param?{ObjectorString}?chunk?參數(shù)chunk應(yīng)當(dāng)是一個(gè)整數(shù)數(shù)組或字符串。?*?@param?{String}?encoding?參數(shù)encoding是可選的,僅在chunk為字符串時(shí)可用。?*/req.write('data\n');/**?*?源API:request.end(chunk,?[encoding])?*?說明:完成本次請求的發(fā)送。如果正文中的任何一個(gè)部分沒有來得及發(fā)送,將把他們?nèi)克⑿碌搅髦?。如果本次請求是分塊的,這個(gè)函數(shù)將發(fā)出結(jié)束字符'0\r\n\r\n'。如果使用參數(shù)data,就等于在調(diào)用request.write(data,?encoding)之后緊接著調(diào)用request.end()。?*?@param?{ObjectorString}?chunk?參數(shù)chunk應(yīng)當(dāng)是一個(gè)整數(shù)數(shù)組或字符串。?*?@param?{String}?encoding?參數(shù)encoding是可選的,僅在chunk為字符串時(shí)可用。?*?example:?req.end(),req.end('data\n'),req.end('data','utf8'),req.end(chunk)?*/req.end();/**?*?阻止一個(gè)請求。(v0.3.8中新增的方法。)?*/req.abort();/**?*?源API:request.setTimeout(timeout,?[callback])?*?說明:一旦給這個(gè)請求分配的是一個(gè)socket時(shí)此函數(shù)會(huì)被調(diào)用?*?@param?{Number}?timeout?毫秒?*?@param?{Function}?callback?回到函數(shù)?*/req.setTimeout(1000,function(){});/**?*?源API?:request.setNoDelay([noDelay])?*?說明:默認(rèn)有一定的延遲,設(shè)置為0表示無延遲?*?@param?{Number}?noDelay?*/req.setNoDelay(0)/**?*?源API:request.setSocketKeepAlive([enable],?[initialDelay])?*?????類似同上?*/
四、http.get
http.get(options,
callback) http 模塊還提供了一個(gè)更加簡便的方法用于處理GET請求:http.get。它是 http.request
的簡化版,唯一的區(qū)別在于http.get自動(dòng)將請求方法設(shè)為了 GET 請求,同時(shí)不需要手動(dòng)調(diào)用 req.end()。
/**
*?Created?by?Administrator?on?14-4-30.
*/varhttp?=require('http');http.createServer(function(req,res){}).listen(3000);/**
*?說明:由于大部分請求是不包含正文的GET請求,Node提供了這個(gè)方便的方法。與http.request()唯一的區(qū)別是此方法將請求方式設(shè)置為GET,并且自動(dòng)調(diào)用req.end()。
*?應(yīng)用:服務(wù)器端測試客服端請求調(diào)試等
*@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);????})