koa2学习笔记:如何优雅组织koa-router多路由文件代码

蛰伏已久 2019-09-10

一个项目肯定会有很多个路由,放到一个文件肯定是不靠谱的,放到多个文件又如何优雅组织代码是个问题。

参照一些PHP框架,我期望将所有的路由放到同一个文件夹,类比一些PHP框架的控制器controllers文件夹,期望路由目录结构如下

--controllers   //改目录下存放我们所有的路由文件
-----site.js     //controllers目录下的文件
-----user.js   //controllers目录下的文件
-----v1       //controllers目录下的文件夹
        ------news.js    //controllers目录下的文件夹v1中的文件


期望最终的路由完整路径 = 路由文件所在目录+路由文件名称+路由文件中定义的路由路径

如:site.js中定义了 router.get('/index',...),则真实路由为 /site/index

       v1文件夹下的news.js中定义了 router.get('/list',...),则真实路由为  /v1/news/list


示例文件内容如下

site.js

var router = require('koa-router')()

router.get('/index',ctx=>{
    ctx.body = 'site index'
})

router.get('/about',ctx=>{
    ctx.body = 'site about'
})


module.exports = router

user.js

var router = require('koa-router')()

router.get('/list',ctx=>{
    ctx.body = 'user list'
})

router.get('/:id',ctx=>{
    ctx.body = 'user detail'
})


module.exports = router

/v1/news.js

var router = require('koa-router')()

router.get('/list',ctx=>{
    ctx.body = 'news list'
})

router.get('/:id',ctx=>{
    ctx.body = 'news detail'
})


module.exports = router


接下来就是如何组织路由了,我们可以利用koa-router的嵌套路由来组织我们所有的路由

const router = require('koa-router')()
router.use(路由前缀, 其他路由.routes(), 其他路由.allowedMethods());

参见 我们上一篇文章:http://shanhuxueyuan.com/news/detail/128.html


我们可以遍历controllers下的所有文件,然后将 文件所在目录及文件名 作为路由前缀,在使用require引入单个文件的路由设置,通过嵌套路由组成我们最终的路由。


在app.js中完成这个功能

app.js

const Koa = require('koa')
const fs = require('fs')
const path = require('path')
let router = require('koa-router')()

const app = new Koa()



let base_path = __dirname + '/controllers'    //要遍历文件所在目录,我们固定为 congtrollers文件夹
let file_path = '/'                           //默认文件路由为/



requireRouters(base_path,file_path)

function requireRouters(base_path,file_path){

    let files = fs.readdirSync(base_path + file_path);  //读取目录下的文件
    
    //遍历所有文件
    files.forEach(file=>{
          
        let file_name = base_path + file_path + file  //完整文件名
        if(fs.statSync(file_name).isFile() && path.extname(file_name)==='.js'){    //如果是文件且是js后缀文件
  
          
           let inner_router = require(file_name)  //require这个文件

           let base_router = file_path + file.substring(0,file.length-3)  //文件所在目录+文件名,作为路由前缀
 
           router.use(base_router,inner_router.routes())   //通过嵌套路由方式设置真实的路由
       

        }else{
            requireRouters(base_path,`${file_path}${file}/`)  //如果是文件夹,则遍历这个文件夹
        }

    })
}



app.use(router.routes());   // 添加路由中间件

app.listen(3031)


通过以上方式即组成我们最终的路由,后续我们想要添加路由,只需要在controllers中添加文件即可,不需要在别的地方进行任何修改,非常方便。


以上代码都放在app.js中感觉不太理想,因为app.js中可能要有很多逻辑,所以可以把这部分抽出来,以中间件的形式在app.js中引入,实现的结果,我们期望如下

const Koa = require('koa')
const app = new Koa()
let composeRouter = require('./middleware/composeRouter')

app.use(composeRouter(__dirname + '/controllers').routes()); //传入路由所在文件夹即可


app.listen(3031)

composeRouter实现

const fs = require('fs')
const path = require('path')
const router = require('koa-router')()


function requireRouters(base_path,file_path){
    let files = fs.readdirSync(base_path + file_path);
    files.forEach(file=>{
        let file_name = base_path + file_path + file
        if(fs.statSync(file_name).isFile() && path.extname(file_name)==='.js'){
            let inner_router = require(file_name)
            let base_router = file_path + file.substring(0,file.length-3)
            router.use(base_router,inner_router.routes())
        }else{
            requireRouters(base_path,`${file_path}${file}/`)
        }

    })
}

module.exports = (routerPath)=>{
    let base_path = routerPath
    let file_path = '/'
    requireRouters(base_path,file_path)
    return router
}

通过中间件的形式,让我们的app.js文件更简洁可读

-END-

点赞(2)