本篇文章給大家分享的是有關(guān)Node中怎么處理HTTP請(qǐng)求,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
目前成都創(chuàng)新互聯(lián)公司已為成百上千家的企業(yè)提供了網(wǎng)站建設(shè)、域名、雅安服務(wù)器托管、網(wǎng)站托管維護(hù)、企業(yè)網(wǎng)站設(shè)計(jì)、閻良網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。
首先使用express generator快速搭建一個(gè)express項(xiàng)目,命令:
express analysis_http
按照提示進(jìn)入項(xiàng)目安裝依賴,然后使用npm start可以啟動(dòng)express項(xiàng)目。那究竟我們項(xiàng)目是如何創(chuàng)建http服務(wù)器并且進(jìn)行啟動(dòng)的呢?express創(chuàng)建成功會(huì)在bin文件夾下生成www文件,里面有必須的啟動(dòng)配置。我們可以看看www文件:
我們初步可以看到,主要調(diào)用了http.createServer()和 server.listen()兩個(gè)方法。我們現(xiàn)在可能會(huì)有一系列疑問:
接口使用的req和res參數(shù)從何而來?createServer()如何創(chuàng)建服務(wù)器?listen()具體是進(jìn)行了什么樣的操作?
接下來,我們通過源碼來具體分析這些問題。首先,從gitHub拉取一份NodeJS源碼,地址:
https://github.com/nodejs/node.git
我們先來查看lib/http.js文件關(guān)鍵代碼:
我們可以看到createServer()方法返回的是Server的一個(gè)實(shí)例。而參數(shù)requestListener我們我們接口中的傳入的回調(diào)函數(shù):
function(req, res, next) { res.send('respond with a resource');}
在文件頂部可以看到Server引用的_http_server.js。所以我們?nèi)?strong>_http_server.js中看看Server這個(gè)構(gòu)造函數(shù):
由于Server繼承net.Server,而net.Server繼承自events.EventEmitter所以可以使用on等方法。我們可以看到在Server構(gòu)造函數(shù)中設(shè)置了request和connection事件的回調(diào)函數(shù):
request使用了createServer中設(shè)置的回調(diào)方法requestListener。connection則使用了回調(diào)方法:connectionListener。
那我們什么時(shí)候會(huì)觸發(fā)connection事件呢?我們看下connectionListener關(guān)鍵源碼:
這里比較需要注意的有parser對(duì)象以及parseOnIncoming()。我們先來看看parser對(duì)象,parser來自parsers.alloc():
const parser = parsers.alloc();
從文件頂部可以看出parsers來自_http_common.js文件。我們可以看看源碼:
我們可以看到,為了盡可能增加對(duì)parser進(jìn)行重用,減少不斷調(diào)用構(gòu)造函數(shù)的消耗,parser采用了FreeList的數(shù)據(jù)結(jié)構(gòu),FreeList池中設(shè)有上限1000,parser是基于事件,使用了http-parser庫。然后可以看到兩個(gè)比較重要的方法:parseOnHeadersComplete和parserOnMessageComplete。
parseOnHeadersComplete:請(qǐng)求頭解析完成則觸發(fā)本方法。parserOnMessageComplete:接收body完成后觸發(fā)本方法,數(shù)據(jù)接收完成會(huì)觸發(fā)end事件。
我們?cè)賮砜纯?strong>FreeList的源碼:
http默認(rèn)創(chuàng)建了1000個(gè)http_parser實(shí)例,每次有http請(qǐng)求時(shí),都會(huì)從數(shù)組中去除一個(gè)http_parser分配給當(dāng)前的socket。如果1000個(gè)http_parser全部分配完畢,則會(huì)分配新的http_parser。我們解析完請(qǐng)求頭會(huì)觸發(fā)parseOnHeadersComplete方法,如果不是udp類型請(qǐng)求,就會(huì)觸發(fā)request事件。
講完了parser對(duì)象,我們接著回到剛才說的parseOnInComing()方法。parseOnInComing()方法使用bind,并傳入?yún)?shù)parser,socket,state。
parser.onIncoming = parserOnIncoming.bind(undefined, server, socket, state);
我們先看看parseOnInComing()的源碼:
里面有個(gè)重要的判斷為sockket._httpMessage。如果結(jié)果為true,說明有其他請(qǐng)求在占用socket。而parserOnInComing()方法用來處理解析完畢的請(qǐng)求,所以到這里代表解析請(qǐng)求頭和請(qǐng)求體已經(jīng)完成了。而剛才已經(jīng)講過:請(qǐng)求頭解析完畢會(huì)執(zhí)行parserOnHeadersComplete()方法,我們看看parserOnHeadersComplete()方法的源碼:
我們可以看到里面調(diào)用了parser.incoming,parser.incoming則是ParserInComingMessage(socket)的一個(gè)實(shí)例。ParserInComingMessage繼承自Stream.Readable。而Stream是NodeJS另一個(gè)尤其重要的知識(shí)點(diǎn),不過本篇文章不進(jìn)行深入講解。
Object.setPrototypeOf(IncomingMessage.prototype, Stream.Readable.prototype);Object.setPrototypeOf(IncomingMessage, Stream.Readable);
所以整體的邏輯應(yīng)該為:
1.解析請(qǐng)求頭,就會(huì)觸發(fā)request事件。2.請(qǐng)求頭解析完畢執(zhí)行parserOnHeadersComplete()方法。3.在parserOnHeadersComplete()方法中執(zhí)行了parseOnIncoming()方法。4.最后server.emit('request', req, res)。
在觸發(fā)request事件的時(shí)候,傳入req, res參數(shù)。因?yàn)橐婚_始我們說過了request綁定了回調(diào)方法:
function(req, res, next) { res.end('respond with a resource');}
所以觸發(fā)request的時(shí)候回調(diào)方法被執(zhí)行。但是body數(shù)據(jù)不會(huì)被解析,而body數(shù)據(jù)會(huì)一直存放在stream中,直到用戶觸發(fā)data事件來接收body中的數(shù)據(jù)?;卣{(diào)方法中會(huì)觸發(fā)res.end()事件。那究竟listen()是做了什么操作呢?
因?yàn)橹挥?strong>connection事件被觸發(fā),才會(huì)觸發(fā)listen()事件。所以先看下onconnection()源碼:
我們接著查看調(diào)用onconnection()方法的源碼:
setupListenHandle(address, port, addressType, backlog, fd)
可以看到底部使用了_listen2。我們繼續(xù)查看調(diào)用_listen2源碼:
可以看到內(nèi)部調(diào)用了server._listen2。我們?cè)俅尾榭凑{(diào)用listenInCluster的源碼:
我們是使用遞推,由下往上推出調(diào)用的方法,所以整體的流程應(yīng)該是:
1.listen()調(diào)用listenInCluster(this, pipeName, -1, -1, backlog, undefined, options.exclusive);2.在listenInCluste()中調(diào)用server._listen2(address, port, addressType, backlog, fd, flags);3.接著調(diào)用了setupListenHandle(address, port, addressType, backlog, fd, flags);4.在setupListenHandle()中調(diào)用了onconnection()。5.最終回到listen()方法并且self.emit('connection', socket);
以上就是Node中怎么處理HTTP請(qǐng)求,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見到或用到的。希望你能通過這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
網(wǎng)站名稱:Node中怎么處理HTTP請(qǐng)求
本文網(wǎng)址:http://www.rwnh.cn/article4/pgcjoe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)建站、用戶體驗(yàn)、網(wǎng)站排名、電子商務(wù)、面包屑導(dǎo)航、網(wǎng)站策劃
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)