上一篇介绍了架构设计,这一篇,结合代码,讲讲怎么实现,和为啥这样实现
先上github:https://github.com/fshwc/hwc_...html
index.js是入口文件,在这个入口文件主要须要作什么呢?
一、启动服务
二、定义各类中间件
三、初始化路由
上面都是一个简单服务必须的,还有一些跟系统稳定相关的,例如combo、pm2等模块,这些就先不实现了。而一个好的模块化和强阅读性,不一样功能的写在不一样的模块里,index.js里就引用就行了,不要所有写在一个js里。
下面是简化后的index.js。node
const express = require('express') const app = express() const middleware = [ {path: './middleware/logger', name: 'logger'}, {path: './middleware/router', name: 'router'}, ] middleware.forEach(function(m) { middleware.__defineGetter__(m.name, function() { return require(m.path) }) }) app.use('*', function(req, res, next) { middleware.logger(req) //各类中间件挂载到req上 next() }) app.use(middleware.router()); //初始化路由 app.all('*', function(req, res) { res.json({error: {msg: 'no found'}}) }) app.listen('8000', () => {})
express里的路由定义是app.get(url, cb)
、app.post(url, cb)
,利用这一个特色,咱们把method、url、cb参数化,app[method](url, cb)
。
在router这个文件夹下,咱们把各类路由经过必定的格式定义。首先这个是能够根据实际场景改变。如今假设是一个多页面系统。view下定义的路由都是要render一个页面的,apis下定义的都是ajax请求。
*路由定义在router路径下,执行方法定义在controller路径下。git
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
。作到,只修改一个方法,就可全局生效。github
const router = express.Router() let apis = [] let dir = path.join(__dirname, '../router') let list = fs.readdirSync(dir) if(list) { list.forEach(files => { var file = require(path.join(__dirname, '../router/'+files)) if(file.apis) apis = apis.concat(file.apis) }) } function applyController(fnPath, req, res, ...args) { var fn = require(path.join(__dirname, '../controller/'+fnPath)) if(fn) fn(req, res, ...args); } function checkPerm(perm, cb) => { if(perm) { //检查是否经过权限,经过才执行cb cb(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() { return router }
ES6增长了class概念。我这里的class,主要是讲和有其余系统交互的,好比systemA是和帐号相关的,systemB是和内容相关的。这两个系统的鉴权方式都是不一样的。这时候我理解node更多扮演一个中间件的角色。
首先都继承一个service/base.jsajax
//base.js const request = require('request') const log4js = require('../logger/logger') module.exports = class Base { constructor(id) { this.id = id; } request(opts, cb) { let infoLogger = log4js.getLogger(`${this.id}-info`) let errorLogger = log4js.getLogger(`${this.id}-error`) opts = this._requestFilter(opts)// 各个系统鉴权 let body = JSON.stringify(opts) infoLogger.info(body) /*request(opts, (err, res, body) => { if(err) errorLogger.error(JSON.stringify(err)) else if(body && body.error) errorLogger.error(JSON.stringify(body.error)) else cb(err, body) })*/ } _requestFilter(opts) { return JSON.parse(JSON.stringify(opts)) } } //systemA.js const Base = require('./Base') const conf = require('../conf/conf') class systemA extends Base { constructor() { super('systemA') } _requestFilter(opts) { opts.qs = opts.qs || {}; var key = conf.systemA_key; var time = new Date().getTime() var _sign = md5(key+time) opts.qs._sign = sign; opts.qs.ts = time } } mudole.exports = systemA
_requestFilter
方法就是鉴权的方法。经过继承,若是子类存在一样命名的方法,会执行子类的方法。因此,若是咱们要和systemA进行http请求,systemA.request(opts),就能自动加鉴权,还自动打点。并且,收拢一个入口仍是有不少好处,万一有修改,只用改一个地方就全局通用。express