一、前言
目前,HTTP协议是互联网上应用最为广泛的一种网络协议,也是前端er接触最多的一种协议。通过阅读http模块在nodejs中的实现,能够更深入的了解HTTP协议。HTTP协议是基于TCP协议之上的应用层协议,它的实现离不开TCP/IP协议族。而具体到代码实现,http模块依赖于net模块。
如下图所示:在nodejs中,http通过net模块传输数据,得到数据之后依靠HTTP_PARSER对数据进行解析。
二、源码
启动一个HTTP服务
nodejs中启动一个HTTP服务很简单,就是实例化一个Server对象,并且监听某个端口:
const Server = require('./libs/http').Server const server = new Server( function(req, res) { res.writeHead(200) res.end('hello world') }) server.listen(9999)
SERVER类
Server类继承于net.Server,并监听'connection‘事件。
在Server类中,主要做了两件事: 1. 初始化NET模块并建立TCP网络监听 2. 监听自身的request事件
当客户端请求到来的时候,Server实例会首先监听到 'connection' 事件,建立起TCP连接并在connectionListener中暴露出socket对象。接下来,HTTP模块就通过socket对象与客户端进行数据交互。
当一个请求到来后,Server会触发自身的 request 事件,调用 requestListener 方法,即创建Server实例时传入的回调函数。
new Server( function(req, res) { res.writeHead(200) res.end('hello world') })
注: socket对象类似于TCP协议的一个实现,可以通过它与客户端进行数据交互 注: 在 connectionListener 函数中,还初始化了parser实例,并给它绑定了一个 onIncoming 函数 HTTP Parser
整个解析流程在 connectionListener 中进行,socket 通过 'data' 事件获取TCP推入的数据
当socket获取到数据之后,会先对数据进行解析,即:parser.excute(),解析工具是parser。值得说明的是,作者为了实现对 parser 的重用, parser是从一个'FreeList池'中获取的。
... const parser = parsers.alloc() ... connectionListener(socket) { socket.on('data', socketOnData) // TCP推入数据,parser进行解析 function socketOnData(d) { ... const ret = parser.execute(d) ... } }
1、TCP数据到达时, 先执行execute()
2、顺藤摸瓜,我们发现parser.excute 就是 Excute(node_http_parser.cc)。而Excute也只是一个外包而已,具体工作是http_parser_excute(http_parser.c)搞定的。
node_http_parser.cc 只是对 http_parser.c 的一层包装,http_parser.c依靠对外暴露的7个回调周期函数与 node_http_parser.cc 进行数据交互。
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的网络请求,实际情况要更加复杂一些,还有一些细节没有完全搞清。等下次总结、分享,我会尽量把漏掉细节都补上。
以上就是本次为大家分享的全部内容,感谢你对的支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!
昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。
这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。
而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?
更新日志
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]