详解NODEJS的http实现

2020-06-17 07:05:34易采站长站整理

3、http_parser.c只有两类回调:HTTP_CB、HTTP_DATA_CB。通过重载的方式,在这两类函数中注册了8个周期函数,如下图:

4、虽然http_parser注册有8个回调函数,但 node_http_parser.cc 对外只暴露出四个周期函数:

parserOnHeaders

parserOnHeadersComplete

parserOnBody

parserOnMessageComplete

5、当 http_parser.c 解析到 on_headers_complete 时,执行HTTP_CB(on_headers_complete)回调函数,如图:

函数内会执行 kOnHeadersComplete 回调函数,即:parserOnHeadersComplete 函数(common.js)

6、此时请求头解析基本完成,接下来创建一个IncomingMessage的实例,然后把请求头数据包装到该实例上。
执行 onIncoming 回调函数,并把得到的IncomingMessage实例作为参数传递进去。


function parserOnHeadersComplete (versionMajor, versionMinor, headers, method, url, statusCode, statusMessage, upgrade, shouldKeepAlive) {
...
parser.incoming = new IncomingMessage(parser.socket)
parser.incoming.httpVersionMajor = versionMajor
parser.incoming.httpVersionMinor = versionMinor
parser.incoming.httpVersion = versionMajor + '.' + versionMinor
parser.incoming.url = url
...
skipBody = parser.onIncoming(parser.incoming, shouldKeepAlive)

}

7、 在 parserOnIncoming 中,创建一个ServerResponse实例。

具备了req、res两个实例,接下来触发Server监听的 request 事件。

在 Server 实例化时的,requestListener是作为函数参数对 request 事件进行监听的。

8、回到Server创建时:


const server = new Server( function(req, res) {
var data = ''
req.on('data', function(chunk){
console.log('chunk: ' + chunk)
data += chunk;
})
res.writeHead(200)
res.end('hello world')
})

综上所述,http_parser 解析完 header 之后,就会触发 request 事件。

那body数据放到哪里呢,其实body数据会一直放到流里面,直到用户使用data事件接收数据。也就是说,触发request的时候,body并不会被解析。

三、流程梳理

完整的http请求是这样的: – 客户端发起HTTP请求,首先触发Server端的connection事件,建立TCP链接。

Server接收到connection事件后,建立TCP连接,并暴露出套接字,通过套接字监听’data’事件;初始化http-parser,为后续解析数据备用。

HTTP请求数据到达Server端,parser执行execute方法进行解析,请求头解析成功后,通过回调触发request事件。

至此,我们在Server回调函数中,就接收到了此次http请求的request

四、结语

由于nodejs不少底层库都是C++/C编写的,在阅读、调试的过程中非常不便。我自己在读源码的时候,也只是着重看的JS部分源码。比如,TCP的三次握手、四次挥手,就没深究它的实现细节啦。 以上分析没有涉及到http-body的解析,对于有body的网络请求,实际情况要更加复杂一些,还有一些细节没有完全搞清。等下次总结、分享,我会尽量把漏掉细节都补上。