当前位置: 首页 > 后端技术 > Node.js

探索ExpressRouter&Route

时间:2023-04-03 23:30:28 Node.js

Express基于Node.js平台,快速、开放、极简的Web开发框架安装//应用生成工具npminstallexpress-generator-g//创建express应用包expressapp//install依赖npminstall生成成功后,会生成如下目录和文件:|---bin|---node_module|---public|---routes|---view|---app。js|---package.json接下来,我们启动程序后通过:npmstart,访问127.0.0.1:3000访问快递页面。接下来,我们将通过研究源码来讨论快速路由原理的实现。路由我们查看app.js和index.js文件:app.jsvarindex=require('./routes/index');app.use('/',index);//或app.get('/',index);routes/index.jsvarexpress=require('express');varrouter=express.Router();router.get('/',function(req,res,next){res.render('index',{title:'Express'});});可以看出express的路由大概定义了一个路由规则文件,然后通过app.use()或者app[METHOD]建立路由规则访问连接,虽然两者的结果是一样的,但是有本质的差异。下图是涉及到的主要文件:接下来我们先通过源码来看一下app.use()的实现思路。app.use我们打开node_module中的express文件夹。打开lib/application.js文件。app.use=functionuse(fn){varoffset=0;变种路径='/';//'/'的默认路径//消除歧义app.use([fn])if(typeoffn!=='function'){vararg=fn;while(Array.isArray(arg)&&arg.length!==0){arg=arg[0];}//第一个参数是路径if(typeofarg!=='function'){offset=1;路径=fn;}}varfns=flatten(slice.call(arguments,offset));if(fns.length===0){thrownewTypeError('app.use()需要中间件函数');}//设置路由器this.lazyrouter();varrouter=this._router;fns.forEach(function(fn){//非expressappif(!fn||!fn.handle||!fn.set){returnrouter.use(path,fn);}debug('.useappunder%s',path);fn.mountpath=path;fn.parent=this;//在req和res上恢复.app属性router.use(path,functionmounted_app(req,res,next){varorig=req.app;fn.handle(req,res,function(err){setPrototypeOf(req,orig.request)setPrototypeOf(res,orig.response)next(err);});});//安装了一个应用程序fn.emit('mount',this);},这);返回这个;};在看到一些使用中的代码后,我们开始判断和处理通过use挂载的路径还是一个函数,通过lazyrouter()方法实例化了router类,全局只有一个router实例对象,并且router.use()方法最终被调用接着,我们到lib/router/index.js看router.use方法的现实:proto.use=functionuse(fn){varoffset=0;变种路径='/';//'/'的默认路径//消除歧义router.use([fn])if(typeoffn!=='function'){vararg=fn;while(Array.isArray(arg)&&arg.length!==0){arg=arg[0];}//第一个参数是路径if(typeofarg!=='function'){offset=1;路径=fn;}}varcallbacks=flatten(slice.call(arguments,offset));if(callbacks.length===0){thrownewTypeError('Router.use()需要中间件函数');}for(vari=0;i')varlayer=newLayer(path,{sensitive:this.caseSensitive,strict:false,end:假},fn);layer.route=undefined;这个.stack.push(层);}返回这个;};通过app.use方法对比,router.use的前半部分处理是一样的,只是后面实例化了一个Layer类,并在Layer类中丢入栈中保存Router和Route的一些数据信息:相同point:path用于存放挂载路径,options.end用于判断是否为路由中间件。区别:Router和Route的区别,一个是添加非路由中间件,一个是添加路由中间件。它们的layer.route点也不一样,一个指向undefined,一个没有route属性。在文章的中间,我们做一个简单的总结。app.use()方法用于添加非路由中间件,最后调用router实例方法,会实例化一个用于存储数据的Layer类对象,并将该layer对象推送到router.stack中,只有一个router全球范围内。app[METHOD]下面通过源码来探究路由中间件app[METHOD]的原理:在app.js中将app.use('\',index)改为app.get('\',index)。application.js:methods.forEach(function(method){app[method]=function(path){if(method==='get'&&arguments.length===1){//app.get(setting)returnthis.set(path);}this.lazyrouter();varroute=this._router.route(path);route[method].apply(route,slice.call(arguments,1));返回这个;};});可以看出代码中完成了一个app.get方法的判断过程。当get方法只有一个参数时,就是获取app的局部变量。后面实例化路由器对象,使用路由器上的route方法把返回的对象调用Route类上的route[METHOD]/lib/router/route.jsmethods.forEach(function(method){Route.prototype[method]=function(){varhandles=flatten(slice.call(arguments));for(vari=0;i