node.js connect模块解析

搭建网站时使用的express,是基于connect模块开发的。这篇博客是通过分析connect源码来分析中间件队列处理HTTP请求的过程。源码参考地址:https://github.com/senchalabs/connect/blob/master/index.js。文中如有不正确敬请指出。

在express中我们使用中间件是类似这样的(图片来自http://www.infoq.com/cn/articles/nodejs-connect-module):

 1. 入口文件connect.js一共做了一件事:

export createServer函数。

下图只提取部分(我觉得比较有代表性比较关键)功能的代码。

 2. 所以执行connect() 也就是执行createServer(),具体做了如下事情:

1)返回一个函数app,入口参数为req, res。app有很多属性方法,比如app.use, app.handle, app.listen,也支持事件。app的函数体就是执行app.handle(req, res, next)。

2)为app添加了stack属性,用来保存中间件。初始值为空数组。

 

3. 当执行app.use(require('body-parser').json())的时候执行了什么

1) 首先require('body-parser').json()返回一个函数parser,入口参数为req, res, next。函数执行到最后会调用next();

2) app.use是将{route: '/', handle: parser}加入stack.

同样的道理,app.use的过程是将中间件加入app.stack的过程。server启动前stack中已经有一系列中间件。

 

4. app.listen(3000)

创建server实例:http.createServer(app)。所以app是收到HTTP请求后的回调。

 

5. 当一个HTTP请求到来后,由于回调函数是app, 所以执行app.handle(req, res, next)。此时next是undefined。handle做了以下几件事

1)req.originalUrl = req.originalUrl || req.url。保存初始url

2)var done = next || finalHandler(req, res, {env: env, onerror: logerror})

3)定义next函数并执行。next函数做了以下几件事:

a. 获取下一个中间件。index初始为0

b. 如果layer为undefined, 在下一个事件循环执行done.

c. 取出layer中route, 如果跟当前url不匹配,执行next(), 也就是执行下一个中间件。如果匹配,执行call(layer.handle, route, err, req, res, next)

 

6. call函数做的事情是:

1)执行handle。如果没有错误,直接返回。handle函数中可能还会调用next, 比如bodyParser.json。如果有错误抛出,设置error。

2)如果出现了错误,执行next(error);

7. 中间件队列遍历结束,执行finalHandler。如果某个中间件直接执行res.send之类的操作,不再执行next, 请求处理结束。

 

所以请求从发送到返回的过程就是req被若干个中间件函数处理,每个函数对req有一点修改,然后传递给下一个中间件函数。next函数是一个闭包,并且一直作为参数被传递,index共享。

 

posted @ 2016-10-28 17:39  Angela多多  阅读(1963)  评论(0编辑  收藏  举报