其实我们前面已经隐含了中间件,从前面的结构可以看出,一个网络请求过来,会到router的第一个layer,然后调用next到到第二个layer,匹配上layer的path就执行回调,然后一直这样把所有的layer都走完。所以中间件是啥?中间件就是一个layer,他的path默认是/,也就是对所有请求都生效。按照这个思路,代码就简单了:
// application.js // app.use就是调用router.use app.use = function use(fn) { var path = "http://www.likecs.com/"; this.lazyrouter(); var router = this._router; router.use(path, fn); };然后在router.use里面再加一层layer就行了:
proto.use = function use(path, fn) { var layer = new Layer(path, fn); this.stack.push(layer); }; 总结Express也是用原生APIhttp.createServer来实现的。
Express的主要工作是将http.createServer的回调函数拆出来了,构建了一个路由结构Router。
这个路由结构由很多层layer组成。
一个中间件就是一个layer。
路由也是一个layer,layer上有一个path属性来表示他可以处理的API路径。
path可能有不同的method,每个method对应layer.route上的一个layer。
layer.route上的layer虽然名字和router上的layer一样,但是功能侧重点并不一样,这也是源码中让人困惑的一个点。
layer.route上的layer的主要参数是method和handle,如果method匹配了,就执行对应的handle。
整个路由匹配过程其实就是遍历router.layer的一个过程。
每个请求来了都会遍历一遍所有的layer,匹配上就执行回调,一个请求可能会匹配上多个layer。
总体来看,Express代码给人的感觉并不是很完美,特别是Layer类肩负两种职责,跟软件工程强调的单一职责原则不符,这也导致Router,Layer,Route三个类的调用关系有点混乱。而且对于继承和原型的使用都是很老的方式。可能也是这种不完美催生了Koa的诞生,下一篇文章我们就来看看Koa的源码吧。
Express其实还对原生的req和res进行了扩展,让他们变得更好用,但是这个其实只相当于一个语法糖,对整体架构没有太大影响,所以本文就没涉及了。
本文可运行代码已经上传GitHub,拿下来一边玩代码,一边看文章效果更佳:https://github.com/dennis-jiang/Front-End-Knowledges/tree/master/Examples/Node.js/Express
参考资料Express官方文档:
Express官方源码:https://github.com/expressjs/express/tree/master/lib
文章的最后,感谢你花费宝贵的时间阅读本文,如果本文给了你一点点帮助或者启发,请不要吝啬你的赞和GitHub小星星,你的支持是作者持续创作的动力。