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

Node架构系列-基础框架代码

时间:2023-04-03 20:16:19 Node.js

上一篇介绍了架构设计。本文结合代码,讲一下如何实现,以及为什么要这样实现。先去github:https://github.com/fshwc/hwc_...index.jsindex.js是入口文件,这个入口文件里面应该做什么?1.启动服务2.定义各种中间件3.初始化路由以上都是一个简单服务所必需的,还有一些关系到系统稳定性的,比如combo,pm2等模块,暂不实现。而且模块化好,可读性强,不同的功能写在不同的模块中,在index.js中引用即可,不要全部写在一个js中。下面是简化的index.js。constexpress=require('express')constapp=express()constmiddleware=[{path:'./middleware/logger',name:'logger'},{path:'./middleware/router',name:'router'},]middleware.forEach(function(m){middleware.__defineGetter__(m.name,function(){returnrequire(m.path)})})app.use('*',function(req,res,next){middleware.logger(req)//挂载各种中间件到reqnext()})app.use(middleware.router());//初始化路由app.all('*',function(req,res){res.json({error:{msg:'nofound'}})})app.listen('8000',()=>{})routingexpress中的路由定义是app.get(url,cb),app.post(url,cb),利用这个特性,我们参数化method,url,cb,app[method](url,cb)。在router文件夹下,我们按照一定的格式定义各种路由。首先,这个可以根据实际场景更改。现在假设一个多页面系统。view下定义的路由都是渲染一个页面,apis下定义的路由都是ajax请求。*route定义在router路径下,执行方法定义在controller路径下。module.exports={view:[{path:'/home',controller:'/home',view:'/home.html'}],apis:[{path:'/getList',method:'get',controller:'/getList',role:['perm1','perm2'],desc:'获取数据列表',}]}这个有个好处,看middleware/router.js,我们是怎么初始化路由的你可以在一个入口检查权限。只要缺少权限,就会统一res.json(error)。如果权限验证通过,就会执行controller中的方法。还有一个潜在的好处,如果执行方法要使用generator方法,只在applyController中,兼容co或await。做吧,只修改一个方法,就可以全局生效。constrouter=express.Router()letapis=[]letdir=path.join(__dirname,'../router')letlist=fs.readdirSync(dir)if(list){list.forEach(files=>{varfile=require(path.join(__dirname,'../router/'+files))if(file.apis)apis=apis.concat(file.apis)})}functionapplyController(fnPath,req,res,...args){varfn=require(path.join(__dirname,'../controller/'+fnPath))if(fn)fn(req,res,...args);}functioncheckPerm(perm,cb)=>{if(perm){//检查权限是否通过,然后执行cbcb(true)//权限不足//cb(null)}}if(apis&&apis.length){apis.forEach(m=>{router[m.method](m.path,(req,res)=>{if(m.perm){checkPerm(m.perm,(hasPerm)=>{if(hasPerm){applyController(m.controller,req,res)}else{res.json({error:{msg:'缺少权限'}})}})}else{applyController(m.controller,req,res)}})})}module.exports=function(){returnrouter}ClassES6增加了类的概念我这里的类主要是和其他系统交互例如,systemA与账号相关,systemB与内容相关。两个系统的认证方式不同。这时候,我明白node更多的是扮演一个中间件的角色。首先都继承一个service/base.js//base.jsconstrequest=require('request')constlog4js=require('../logger/logger')module.exports=classBase{constructor(id){this.编号=编号;}request(opts,cb){letinfoLogger=log4js.getLogger(`${this.id}-info`)leterrorLogger=log4js.getLogger(`${this.id}-error`)opts=this._requestFilter(opts)//各个系统鉴定权letbody=JSON.stringify(opts)infoLogger.info(body)/*request(opts,(err,res,body)=>{if(err)errorLogger.error(JSON.stringify(err))elseif(body&&body.error)errorLogger.error(JSON.stringify(body.error))elsecb(err,body)})*/}_requestFilter(opts){returnJSON.parse(JSON.stringify(opts))}}//systemA.jsconstBase=require('./Base')constconf=require('../conf/conf')classsystemAextendsBase{构造函数(){super('systemA')}_requestFilter(opts){opts.qs=opts.qs||{};varkey=conf.systemA_key;vartime=newDate().getTime()var_sign=md5(key+time)opts.qs._sign=sign;opts.qs.ts=time}}mudole.exports=systemA_requestFilter方法是认证的方法。通过继承,如果子类中有同名方法,则执行子类的方法。因此,如果我们要向systemA发起http请求,systemA.request(opts),可以自动添加鉴权,自动管理。而且,关闭一个入口还是有很多好处的。修改时只需改一处即可通用。