node架構系列-基礎框架代碼

上一篇介紹了架構設計,這一篇,結合代碼,講講怎麼實現,和爲啥這樣實現
先上github:https://github.com/fshwc/hwc_...html

index.js

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裏,兼容coawait。作到,只修改一個方法,就可全局生效。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
}

Class

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

相關文章
相關標籤/搜索