什么是路由
路由就是具体的访问路径,指向特定的功能模块。一个
api
接口是由ip(域名)+端口号
+路径组成,例如 :https://www.npmjs.com/package/koa-router
就是一个路由,指向了koa-router
的npm
页面。
为什么需要 koa-router 路由
当然不需要koa-router
也能实现路由功能,通过ctx.request.path
去指定路径实现。例子如下:
const koa = require('koa2')
const app = new koa()
app.use(async (ctx, next) => {
if (ctx.request.path === '/') { // 首页
ctx.response.status = 200
ctx.response.body = 'index'
} else if (ctx.request.path === '/list') { // 列表页
ctx.response.status = 200
ctx.response.body = 'list'
} else {
ctx.throw(404, 'Not found') // 404
}
await next()
})
app.listen(3000)
以上代码只是实现两个接口,就写了不少代码,而写是多层的判断代码,可读性已经很差了,这时候怎么办?
是不是可以将以上代码抽取出去,通过中间件的方式去实现。
结果是可以的,koa-router
就是这样做的。使用koa-router
实现的例子如下:
- app.js 入口
- urls/home.js home 页面的路由
app.js
的代码如下
// 路由模块使用前需要先安装和实例化
const Router = require('koa-router')
const router = new Router()
// 首页
app.use(async (ctx, next) => {
if (ctx.request.path === '/') {
ctx.response.status = 200
ctx.response.body = 'index'
}
await next()
})
// 其他页面通过 router 加载
let urls = fs.readdirSync(__dirname + '/urls')
urls.forEach((element) => {
let module = require(__dirname + '/urls/' + element)
/*
urls 下面的每个文件负责一个特定的功能,分开管理
通过 fs.readdirSync 读取 urls 目录下的所有文件名,挂载到 router 上面
*/
router.use('/' + element.replace('.js', ''), module.routes(), module.allowedMethods())
})
app.use(router.routes())
urls/home.js
的代码如下
const Router = require('koa-router')
const home = new Router()
// /home
home.get('/', async (ctx, next) => {
ctx.response.status = 200
ctx.response.body = 'home'
await next()
})
// home/list
home.get('/list', async (ctx, next) => {
ctx.response.status = 200
ctx.response.body = 'home-list'
await next()
})
module.exports = home
通过以上代码基本已经实现了全局路由的功能
了,剩下得就是在urls
包下创建对应的文件即可,参考home.js
即可。
但是这里的代码还是不够完美,app.js
作为入口文件,这里的代码还是有点多了;而且首页和home
的路由是分开来实现的。再而且urls
路径是固定的,后续文件夹名称或者位置改变都会出现问题。
那么如何实现呢?
这里介绍一种思路:
- 将
app.js
中的代码抽取出来,让app.js
尽量简单 - 将首页和其他页面都在全局路由中实现
优雅的全局路由实现
通过npm
引入require-directory
require-directory npm
包的作用是:
递归地遍历指定目录,对每个文件进行require()
这里也是利用了这个包去实现的。具体实现如下:
- 在
core
目录下创建InitManager.js
const requireDirectory = require('require-directory')
const Router = require('koa-router')
/**
* 加载全局路由
*/
static initLoadRouters(app){
// 加载工作目录下的 app/api 下的路径
const apiDirectory = `${process.cwd()}/app/api`
// 参数:第一个参数固定参数module
// 第二个参数要加载的模块的文件路径
// 第三个参数:每次加载一个参数执行的函数
requireDirectory(module, apiDirectory, {
visit: whenLoadModule
})
function whenLoadModule(obj) {
if(obj instanceof Router ){
app.use(obj.routes())
}
}
}
module.exports = InitManager
从上面的实现方式可以看出这里使用了process.cwd()
获取路径,而原有的代码中是通过__dirname
去获取路径,那么二者有什么区别呢?
NodeJs
中process.cwd()
与__dirname
的区别
process.cwd()
是当前执行node
命令时候的文件夹地址 ——工作目录,保证了文件在不同的目录下执行时,路径始终不变
__dirname
是被执行的js
文件的地址 ——文件所在目录
- 在
app.js
中加载这个方法即可。
const app = new Koa()
InitManager.initLoadRouters(app)
- 在
app/api
下创建相应的接口文件即可,如home.js
咨询请加微信:轻撩即可。