Express框架接触了很久。刚接触的时候觉得Express框架晦涩难懂,有点头晕。最近准备再翻一遍Express源码。一方面是给自己做笔记,方便以后看。示例代码开始前,这里不细说如何启动express项目,但总的来说,有以下常用代码varexpress=require('express');//index下的路由规则varindex=require('./routes/index');//用户下的路由规则varusers=require('./routes/users');varapp=express();app.use('/',index);app.use('/users',users);//监听3000端口app.listen(3000,()=>{console.log("listening....")});这里我们重点关注导入用户。js依赖包,因为这个跟get请求的路由有关,代码如下varexpress=require('express');varrouter=express.Router();/*GETuserslisting.*/router.get('/',function(req,res,next){res.json({name:1});next();},function(req,res,next){console.log("nextaaaa")});router.get('/aaa',function(req,res,next){next();},function(req,res,next){res.json({a:1});next();},function(req,res){console.log("next",2222);});module.exports=router;源码分析从示例代码中我们不难看出,最重要的代码是app.use,use的内部存储是中间件。当路由地址匹配时,这些中间件会依次流过。但是在使用中间件的时候,首先要做的就是初始化路由。lazyrouter内部初始化路由并自动添加两个新的中间件。app.lazyrouter=functionlazyrouter(){if(!this._router){this._router=newRouter({caseSensitive:this.enabled('区分大小写的路由'),strict:this.enabled('严格路由')});this._router.use(query(this.get('queryparserfn')));this._router.use(middleware.init(this));}};经过这么多的准备,最终构建的路由器对象[1]有如下形式/**路由器方法对象内部属性为:router.params={};router._params=[];router.caseSensitive=opts.caseSensitive;router.mergeParams=opts.mergeParams;路由器.strict=opts.strict;router.stack=[];**/functionrouter(req,res,next){router.handle(req,res,next);}这里值得一提的是express里面的巧妙实现methods.concat('all').forEach(function(method){proto[method]=function(path){varroute=this.route(path)//这里将方法内部的属性方法的this改成路由对象,并传值给route.getroute[method].apply(route,slice.call(arguments,1));returnthis;};});等方法参数中除第一个路径参数外的所有回调函数原型。route=functionroute(路径){varroute=newRoute(路径);varlayer=newLayer(path,{sensitive:this.caseSensitive,strict:this.strict,end:true},route.dispatch.bind(route));layer.route=路线;这个.stack.push(layer);回程;};通过遍历所有的方法,在proto中添加get方法和方法的其他内部属性,首先要搞清楚this指的是谁,this指的是当前的router对象,即express.Router(),其中包含相同的数据结构如[1]中的router对象,因为是get请求,所有layer.route都是构造的子路由对象,每一个get请求route都添加到Layer对象中,每一个get,post等请求对应一个Layer对象,最终被压入新栈让我们看看内部层对象。我觉得最重要的是设置路由正则规则和存储句柄函数}debug('new%o',path)varopts=options||{};this.handle=fn;this.name=fn.name||'<匿名>';this.params=undefined;这个。路径=未定义;this.regexp=pathRegexp(path,this.keys=[],opts);//setfastpathflagsthis.regexp.fast_star=path==='*'this.regexp.fast_slash=path==='/'&&opts.end===false}第二个神奇巧妙的地方是varroute=newRoute(path);,加载内部子路由时,就像第一个触发后,会出现山海一样卡片组成的美景,内部实现文件会自动实现为一旦他们被感动。函数路由(路径){this.path=path;这个.stack=[];debug('new%o',path)//各种http方法的路由处理程序this.methods={};}methods.forEach(function(method){Route.prototype[method]=function(){varhandles=flatten(slice.call(arguments));for(vari=0;i
